@rmdes/indiekit-endpoint-activitypub 2.7.1 → 2.8.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/reader-links.css +3 -3
- package/assets/reader.css +144 -29
- package/lib/jf2-to-as2.js +20 -4
- package/package.json +1 -1
- package/views/activitypub-profile.njk +7 -3
- package/views/activitypub-reader.njk +1 -2
- package/views/activitypub-remote-profile.njk +3 -5
- package/views/layouts/ap-reader.njk +4 -2
- package/views/partials/ap-item-card.njk +5 -6
- package/views/partials/ap-item-media.njk +2 -2
- package/views/partials/ap-notification-card.njk +3 -6
package/assets/reader-links.css
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
.ap-link-preview {
|
|
16
16
|
display: flex;
|
|
17
17
|
overflow: hidden;
|
|
18
|
-
border-radius:
|
|
19
|
-
border:
|
|
18
|
+
border-radius: var(--border-radius-small);
|
|
19
|
+
border: var(--border-width-thin) solid var(--color-outline);
|
|
20
20
|
background-color: var(--color-offset);
|
|
21
21
|
text-decoration: none;
|
|
22
22
|
color: inherit;
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
letter-spacing: 0.05em;
|
|
122
122
|
margin: var(--space-l) 0 var(--space-s);
|
|
123
123
|
padding-bottom: var(--space-xs);
|
|
124
|
-
border-bottom:
|
|
124
|
+
border-bottom: var(--border-width-thin) solid var(--color-outline);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
.ap-post-detail__main {
|
package/assets/reader.css
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
|
|
33
33
|
.ap-breadcrumb__current {
|
|
34
34
|
color: var(--color-on-background);
|
|
35
|
-
font-weight:
|
|
35
|
+
font-weight: 600;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/* ==========================================================================
|
|
@@ -151,10 +151,10 @@
|
|
|
151
151
|
background: var(--color-offset);
|
|
152
152
|
border: var(--border-width-thin) solid var(--color-outline);
|
|
153
153
|
border-left: 3px solid var(--color-outline);
|
|
154
|
-
border-radius:
|
|
154
|
+
border-radius: var(--border-radius-small);
|
|
155
155
|
overflow: hidden;
|
|
156
156
|
padding: var(--space-m);
|
|
157
|
-
box-shadow: 0 1px 2px
|
|
157
|
+
box-shadow: 0 1px 2px hsl(var(--tint-neutral) 10% / 0.04);
|
|
158
158
|
transition:
|
|
159
159
|
box-shadow 0.2s ease,
|
|
160
160
|
border-color 0.2s ease;
|
|
@@ -163,7 +163,7 @@
|
|
|
163
163
|
.ap-card:hover {
|
|
164
164
|
border-color: var(--color-outline-variant);
|
|
165
165
|
border-left-color: var(--color-outline-variant);
|
|
166
|
-
box-shadow: 0 2px 8px
|
|
166
|
+
box-shadow: 0 2px 8px hsl(var(--tint-neutral) 10% / 0.08);
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
/* ==========================================================================
|
|
@@ -261,15 +261,27 @@
|
|
|
261
261
|
margin-bottom: var(--space-s);
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
+
.ap-card__avatar-wrap {
|
|
265
|
+
flex-shrink: 0;
|
|
266
|
+
height: 44px;
|
|
267
|
+
position: relative;
|
|
268
|
+
width: 44px;
|
|
269
|
+
}
|
|
270
|
+
|
|
264
271
|
.ap-card__avatar {
|
|
265
272
|
border: var(--border-width-thin) solid var(--color-outline);
|
|
266
273
|
border-radius: 50%;
|
|
267
|
-
flex-shrink: 0;
|
|
268
274
|
height: 44px;
|
|
269
275
|
object-fit: cover;
|
|
270
276
|
width: 44px;
|
|
271
277
|
}
|
|
272
278
|
|
|
279
|
+
.ap-card__avatar-wrap > img {
|
|
280
|
+
position: absolute;
|
|
281
|
+
inset: 0;
|
|
282
|
+
z-index: 1;
|
|
283
|
+
}
|
|
284
|
+
|
|
273
285
|
.ap-card__avatar--default {
|
|
274
286
|
align-items: center;
|
|
275
287
|
background: var(--color-offset-variant);
|
|
@@ -411,7 +423,7 @@
|
|
|
411
423
|
|
|
412
424
|
.ap-card__content code {
|
|
413
425
|
background: var(--color-offset-variant);
|
|
414
|
-
border-radius:
|
|
426
|
+
border-radius: var(--border-radius-small);
|
|
415
427
|
font-size: 0.9em;
|
|
416
428
|
padding: 1px 4px;
|
|
417
429
|
}
|
|
@@ -508,7 +520,7 @@
|
|
|
508
520
|
========================================================================== */
|
|
509
521
|
|
|
510
522
|
.ap-card__gallery {
|
|
511
|
-
border-radius:
|
|
523
|
+
border-radius: var(--border-radius-small);
|
|
512
524
|
display: grid;
|
|
513
525
|
gap: 2px;
|
|
514
526
|
margin-bottom: var(--space-s);
|
|
@@ -528,12 +540,18 @@
|
|
|
528
540
|
.ap-card__gallery img {
|
|
529
541
|
background: var(--color-offset-variant);
|
|
530
542
|
display: block;
|
|
531
|
-
height:
|
|
543
|
+
height: 280px;
|
|
532
544
|
object-fit: cover;
|
|
533
545
|
width: 100%;
|
|
534
546
|
transition: filter 0.2s ease;
|
|
535
547
|
}
|
|
536
548
|
|
|
549
|
+
@media (max-width: 480px) {
|
|
550
|
+
.ap-card__gallery img {
|
|
551
|
+
height: 180px;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
537
555
|
.ap-card__gallery-link:hover img {
|
|
538
556
|
filter: brightness(0.92);
|
|
539
557
|
}
|
|
@@ -601,7 +619,7 @@
|
|
|
601
619
|
|
|
602
620
|
.ap-lightbox {
|
|
603
621
|
align-items: center;
|
|
604
|
-
background:
|
|
622
|
+
background: hsl(var(--tint-neutral) 10% / 0.92);
|
|
605
623
|
display: flex;
|
|
606
624
|
inset: 0;
|
|
607
625
|
justify-content: center;
|
|
@@ -668,6 +686,83 @@
|
|
|
668
686
|
transform: translateX(-50%);
|
|
669
687
|
}
|
|
670
688
|
|
|
689
|
+
/* ==========================================================================
|
|
690
|
+
Link Preview Card
|
|
691
|
+
========================================================================== */
|
|
692
|
+
|
|
693
|
+
.ap-link-previews {
|
|
694
|
+
margin-bottom: var(--space-s);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
.ap-link-preview {
|
|
698
|
+
display: flex;
|
|
699
|
+
border: var(--border-width-thin) solid var(--color-outline);
|
|
700
|
+
border-radius: var(--border-radius-small);
|
|
701
|
+
overflow: hidden;
|
|
702
|
+
text-decoration: none;
|
|
703
|
+
color: inherit;
|
|
704
|
+
transition: border-color 0.2s ease;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.ap-link-preview:hover {
|
|
708
|
+
border-color: var(--color-primary);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
.ap-link-preview__text {
|
|
712
|
+
flex: 1;
|
|
713
|
+
min-width: 0;
|
|
714
|
+
padding: var(--space-s) var(--space-m);
|
|
715
|
+
display: flex;
|
|
716
|
+
flex-direction: column;
|
|
717
|
+
justify-content: center;
|
|
718
|
+
gap: 0.2em;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
.ap-link-preview__title {
|
|
722
|
+
font-weight: 600;
|
|
723
|
+
font-size: var(--font-size-s);
|
|
724
|
+
margin: 0;
|
|
725
|
+
overflow: hidden;
|
|
726
|
+
text-overflow: ellipsis;
|
|
727
|
+
white-space: nowrap;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
.ap-link-preview__desc {
|
|
731
|
+
font-size: var(--font-size-s);
|
|
732
|
+
color: var(--color-on-offset);
|
|
733
|
+
margin: 0;
|
|
734
|
+
display: -webkit-box;
|
|
735
|
+
-webkit-line-clamp: 2;
|
|
736
|
+
-webkit-box-orient: vertical;
|
|
737
|
+
overflow: hidden;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.ap-link-preview__domain {
|
|
741
|
+
font-size: var(--font-size-xs);
|
|
742
|
+
color: var(--color-on-offset);
|
|
743
|
+
margin: 0;
|
|
744
|
+
display: flex;
|
|
745
|
+
align-items: center;
|
|
746
|
+
gap: 0.3em;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
.ap-link-preview__favicon {
|
|
750
|
+
width: 14px;
|
|
751
|
+
height: 14px;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
.ap-link-preview__image {
|
|
755
|
+
flex-shrink: 0;
|
|
756
|
+
width: 120px;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
.ap-link-preview__image img {
|
|
760
|
+
display: block;
|
|
761
|
+
width: 100%;
|
|
762
|
+
height: 100%;
|
|
763
|
+
object-fit: cover;
|
|
764
|
+
}
|
|
765
|
+
|
|
671
766
|
/* ==========================================================================
|
|
672
767
|
Video Embed
|
|
673
768
|
========================================================================== */
|
|
@@ -778,7 +873,7 @@
|
|
|
778
873
|
align-items: center;
|
|
779
874
|
background: transparent;
|
|
780
875
|
border: 0;
|
|
781
|
-
border-radius:
|
|
876
|
+
border-radius: var(--border-radius-small);
|
|
782
877
|
color: var(--color-on-offset);
|
|
783
878
|
cursor: pointer;
|
|
784
879
|
display: inline-flex;
|
|
@@ -1105,6 +1200,11 @@
|
|
|
1105
1200
|
position: relative;
|
|
1106
1201
|
}
|
|
1107
1202
|
|
|
1203
|
+
.ap-notification__avatar-wrap {
|
|
1204
|
+
height: 40px;
|
|
1205
|
+
width: 40px;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1108
1208
|
.ap-notification__avatar {
|
|
1109
1209
|
border: var(--border-width-thin) solid var(--color-outline);
|
|
1110
1210
|
border-radius: 50%;
|
|
@@ -1113,6 +1213,12 @@
|
|
|
1113
1213
|
width: 40px;
|
|
1114
1214
|
}
|
|
1115
1215
|
|
|
1216
|
+
.ap-notification__avatar-wrap > img {
|
|
1217
|
+
position: absolute;
|
|
1218
|
+
inset: 0;
|
|
1219
|
+
z-index: 1;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1116
1222
|
.ap-notification__avatar--default {
|
|
1117
1223
|
align-items: center;
|
|
1118
1224
|
background: var(--color-offset-variant);
|
|
@@ -1236,7 +1342,16 @@
|
|
|
1236
1342
|
}
|
|
1237
1343
|
|
|
1238
1344
|
.ap-profile__avatar-wrap {
|
|
1345
|
+
height: 80px;
|
|
1239
1346
|
margin-bottom: var(--space-s);
|
|
1347
|
+
position: relative;
|
|
1348
|
+
width: 80px;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
.ap-profile__avatar-wrap > img {
|
|
1352
|
+
position: absolute;
|
|
1353
|
+
inset: 0;
|
|
1354
|
+
z-index: 1;
|
|
1240
1355
|
}
|
|
1241
1356
|
|
|
1242
1357
|
.ap-profile__avatar {
|
|
@@ -1818,7 +1933,7 @@
|
|
|
1818
1933
|
|
|
1819
1934
|
.ap-tag-header__title {
|
|
1820
1935
|
font-size: var(--font-size-xl);
|
|
1821
|
-
font-weight:
|
|
1936
|
+
font-weight: 600;
|
|
1822
1937
|
margin: 0 0 var(--space-xs);
|
|
1823
1938
|
}
|
|
1824
1939
|
|
|
@@ -1945,7 +2060,7 @@
|
|
|
1945
2060
|
border: var(--border-width-thin) solid var(--color-outline);
|
|
1946
2061
|
border-radius: var(--border-radius-small);
|
|
1947
2062
|
box-sizing: border-box;
|
|
1948
|
-
font-size: var(--font-size-
|
|
2063
|
+
font-size: var(--font-size-m);
|
|
1949
2064
|
min-width: 0;
|
|
1950
2065
|
padding: var(--space-xs) var(--space-s);
|
|
1951
2066
|
width: 100%;
|
|
@@ -2011,7 +2126,7 @@
|
|
|
2011
2126
|
background: var(--color-background);
|
|
2012
2127
|
border: var(--border-width-thin) solid var(--color-outline);
|
|
2013
2128
|
border-radius: var(--border-radius-small);
|
|
2014
|
-
box-shadow: 0 4px 12px
|
|
2129
|
+
box-shadow: 0 4px 12px hsl(var(--tint-neutral) 10% / 0.15);
|
|
2015
2130
|
left: 0;
|
|
2016
2131
|
max-height: 320px;
|
|
2017
2132
|
overflow-y: auto;
|
|
@@ -2088,7 +2203,7 @@
|
|
|
2088
2203
|
background: var(--color-background);
|
|
2089
2204
|
border: var(--border-width-thin) solid var(--color-outline);
|
|
2090
2205
|
border-radius: var(--border-radius-small);
|
|
2091
|
-
box-shadow: 0 4px 12px
|
|
2206
|
+
box-shadow: 0 4px 12px hsl(var(--tint-neutral) 10% / 0.15);
|
|
2092
2207
|
left: 0;
|
|
2093
2208
|
max-height: 320px;
|
|
2094
2209
|
overflow-y: auto;
|
|
@@ -2198,7 +2313,7 @@
|
|
|
2198
2313
|
}
|
|
2199
2314
|
|
|
2200
2315
|
.ap-explore-tabs-nav::after {
|
|
2201
|
-
background: linear-gradient(to right, transparent, var(--color-background
|
|
2316
|
+
background: linear-gradient(to right, transparent, var(--color-background) 80%);
|
|
2202
2317
|
content: "";
|
|
2203
2318
|
height: 100%;
|
|
2204
2319
|
pointer-events: none;
|
|
@@ -2267,7 +2382,7 @@
|
|
|
2267
2382
|
|
|
2268
2383
|
/* Scope badges on instance tabs */
|
|
2269
2384
|
.ap-tab__badge {
|
|
2270
|
-
border-radius:
|
|
2385
|
+
border-radius: var(--border-radius-small);
|
|
2271
2386
|
font-size: 0.65em;
|
|
2272
2387
|
font-weight: 700;
|
|
2273
2388
|
letter-spacing: 0.02em;
|
|
@@ -2439,7 +2554,7 @@
|
|
|
2439
2554
|
|
|
2440
2555
|
.ap-explore-tab-error__retry {
|
|
2441
2556
|
background: none;
|
|
2442
|
-
border:
|
|
2557
|
+
border: var(--border-width-thin) solid var(--color-primary-on-background);
|
|
2443
2558
|
border-radius: var(--border-radius-small);
|
|
2444
2559
|
color: var(--color-primary-on-background);
|
|
2445
2560
|
cursor: pointer;
|
|
@@ -2519,7 +2634,7 @@
|
|
|
2519
2634
|
|
|
2520
2635
|
.ap-unread-toggle--active {
|
|
2521
2636
|
background: color-mix(in srgb, var(--color-primary) 12%, transparent);
|
|
2522
|
-
font-weight:
|
|
2637
|
+
font-weight: 600;
|
|
2523
2638
|
}
|
|
2524
2639
|
|
|
2525
2640
|
/* ==========================================================================
|
|
@@ -2528,7 +2643,7 @@
|
|
|
2528
2643
|
|
|
2529
2644
|
.ap-quote-embed {
|
|
2530
2645
|
border: var(--border-width-thin) solid var(--color-outline);
|
|
2531
|
-
border-radius:
|
|
2646
|
+
border-radius: var(--border-radius-small);
|
|
2532
2647
|
margin-top: var(--space-s);
|
|
2533
2648
|
overflow: hidden;
|
|
2534
2649
|
transition: border-color 0.15s ease;
|
|
@@ -2574,7 +2689,7 @@
|
|
|
2574
2689
|
color: var(--color-on-offset);
|
|
2575
2690
|
display: inline-flex;
|
|
2576
2691
|
font-size: var(--font-size-xs);
|
|
2577
|
-
font-weight:
|
|
2692
|
+
font-weight: 600;
|
|
2578
2693
|
justify-content: center;
|
|
2579
2694
|
}
|
|
2580
2695
|
|
|
@@ -2585,7 +2700,7 @@
|
|
|
2585
2700
|
|
|
2586
2701
|
.ap-quote-embed__name {
|
|
2587
2702
|
font-size: var(--font-size-s);
|
|
2588
|
-
font-weight:
|
|
2703
|
+
font-weight: 600;
|
|
2589
2704
|
overflow: hidden;
|
|
2590
2705
|
text-overflow: ellipsis;
|
|
2591
2706
|
white-space: nowrap;
|
|
@@ -2608,7 +2723,7 @@
|
|
|
2608
2723
|
|
|
2609
2724
|
.ap-quote-embed__title {
|
|
2610
2725
|
font-size: var(--font-size-s);
|
|
2611
|
-
font-weight:
|
|
2726
|
+
font-weight: 600;
|
|
2612
2727
|
margin: 0 0 var(--space-xs);
|
|
2613
2728
|
}
|
|
2614
2729
|
|
|
@@ -2674,8 +2789,8 @@
|
|
|
2674
2789
|
position: absolute;
|
|
2675
2790
|
bottom: 0.5rem;
|
|
2676
2791
|
left: 0.5rem;
|
|
2677
|
-
background:
|
|
2678
|
-
color:
|
|
2792
|
+
background: hsl(var(--tint-neutral) 10% / 0.7);
|
|
2793
|
+
color: var(--color-neutral99);
|
|
2679
2794
|
font-size: 0.65rem;
|
|
2680
2795
|
font-weight: 700;
|
|
2681
2796
|
padding: 0.15rem 0.35rem;
|
|
@@ -2688,7 +2803,7 @@
|
|
|
2688
2803
|
}
|
|
2689
2804
|
|
|
2690
2805
|
.ap-media__alt-badge:hover {
|
|
2691
|
-
background:
|
|
2806
|
+
background: hsl(var(--tint-neutral) 10% / 0.9);
|
|
2692
2807
|
}
|
|
2693
2808
|
|
|
2694
2809
|
.ap-media__alt-text {
|
|
@@ -2696,8 +2811,8 @@
|
|
|
2696
2811
|
bottom: 2.2rem;
|
|
2697
2812
|
left: 0.5rem;
|
|
2698
2813
|
right: 0.5rem;
|
|
2699
|
-
background:
|
|
2700
|
-
color:
|
|
2814
|
+
background: hsl(var(--tint-neutral) 10% / 0.85);
|
|
2815
|
+
color: var(--color-neutral99);
|
|
2701
2816
|
font-size: var(--font-size-s);
|
|
2702
2817
|
padding: 0.5rem;
|
|
2703
2818
|
border-radius: var(--border-radius-small);
|
|
@@ -2787,11 +2902,11 @@
|
|
|
2787
2902
|
|
|
2788
2903
|
/* --- Card shadows: use light tint instead of black --- */
|
|
2789
2904
|
.ap-card {
|
|
2790
|
-
box-shadow: 0 1px 2px
|
|
2905
|
+
box-shadow: 0 1px 2px hsl(var(--tint-neutral) 90% / 0.04);
|
|
2791
2906
|
}
|
|
2792
2907
|
|
|
2793
2908
|
.ap-card:hover {
|
|
2794
|
-
box-shadow: 0 2px 8px
|
|
2909
|
+
box-shadow: 0 2px 8px hsl(var(--tint-neutral) 90% / 0.06);
|
|
2795
2910
|
}
|
|
2796
2911
|
|
|
2797
2912
|
/* --- Tab badge federated: soften purple --- */
|
package/lib/jf2-to-as2.js
CHANGED
|
@@ -20,6 +20,22 @@ import {
|
|
|
20
20
|
Video,
|
|
21
21
|
} from "@fedify/fedify/vocab";
|
|
22
22
|
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Content helpers
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Convert bare URLs in HTML content to clickable links.
|
|
29
|
+
* Skips URLs already inside href attributes or anchor tag text.
|
|
30
|
+
*/
|
|
31
|
+
function linkifyUrls(html) {
|
|
32
|
+
if (!html) return html;
|
|
33
|
+
return html.replace(
|
|
34
|
+
/(?<![=">])(https?:\/\/[^\s<"]+)/g,
|
|
35
|
+
'<a href="$1">$1</a>',
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
23
39
|
// ---------------------------------------------------------------------------
|
|
24
40
|
// Plain JSON-LD (content negotiation on individual post URLs)
|
|
25
41
|
// ---------------------------------------------------------------------------
|
|
@@ -68,7 +84,7 @@ export function jf2ToActivityStreams(properties, actorUrl, publicationUrl) {
|
|
|
68
84
|
|
|
69
85
|
if (postType === "bookmark") {
|
|
70
86
|
const bookmarkUrl = properties["bookmark-of"];
|
|
71
|
-
const commentary = properties.content?.html || properties.content || "";
|
|
87
|
+
const commentary = linkifyUrls(properties.content?.html || properties.content || "");
|
|
72
88
|
object.content = commentary
|
|
73
89
|
? `${commentary}<br><br>\u{1F516} <a href="${bookmarkUrl}">${bookmarkUrl}</a>`
|
|
74
90
|
: `\u{1F516} <a href="${bookmarkUrl}">${bookmarkUrl}</a>`;
|
|
@@ -80,7 +96,7 @@ export function jf2ToActivityStreams(properties, actorUrl, publicationUrl) {
|
|
|
80
96
|
},
|
|
81
97
|
];
|
|
82
98
|
} else {
|
|
83
|
-
object.content = properties.content?.html || properties.content || "";
|
|
99
|
+
object.content = linkifyUrls(properties.content?.html || properties.content || "");
|
|
84
100
|
}
|
|
85
101
|
|
|
86
102
|
// Append permalink to content so fediverse clients show a clickable link
|
|
@@ -193,12 +209,12 @@ export function jf2ToAS2Activity(properties, actorUrl, publicationUrl, options =
|
|
|
193
209
|
// Content
|
|
194
210
|
if (postType === "bookmark") {
|
|
195
211
|
const bookmarkUrl = properties["bookmark-of"];
|
|
196
|
-
const commentary = properties.content?.html || properties.content || "";
|
|
212
|
+
const commentary = linkifyUrls(properties.content?.html || properties.content || "");
|
|
197
213
|
noteOptions.content = commentary
|
|
198
214
|
? `${commentary}<br><br>\u{1F516} <a href="${bookmarkUrl}">${bookmarkUrl}</a>`
|
|
199
215
|
: `\u{1F516} <a href="${bookmarkUrl}">${bookmarkUrl}</a>`;
|
|
200
216
|
} else {
|
|
201
|
-
noteOptions.content = properties.content?.html || properties.content || "";
|
|
217
|
+
noteOptions.content = linkifyUrls(properties.content?.html || properties.content || "");
|
|
202
218
|
}
|
|
203
219
|
|
|
204
220
|
// Append permalink to content so fediverse clients show a clickable link
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rmdes/indiekit-endpoint-activitypub",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.1",
|
|
4
4
|
"description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"indiekit",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
<label class="label" for="link_value_{{ loop.index }}">{{ __("activitypub.profile.linkValueLabel") }}</label>
|
|
92
92
|
<input class="input" type="url" id="link_value_{{ loop.index }}" name="link_value[]" value="{{ att.value }}" placeholder="https://example.com">
|
|
93
93
|
</div>
|
|
94
|
-
<button type="button" class="button button--small
|
|
94
|
+
<button type="button" class="button button--small profile-link-remove" style="margin-block-end: 4px;">{{ __("activitypub.profile.removeLink") }}</button>
|
|
95
95
|
</div>
|
|
96
96
|
{% endfor %}
|
|
97
97
|
{% endif %}
|
|
@@ -129,6 +129,11 @@
|
|
|
129
129
|
|
|
130
130
|
<script>
|
|
131
131
|
(function() {
|
|
132
|
+
document.getElementById('profile-links').addEventListener('click', function(e) {
|
|
133
|
+
var btn = e.target.closest('.profile-link-remove');
|
|
134
|
+
if (btn) btn.closest('.profile-link-row').remove();
|
|
135
|
+
});
|
|
136
|
+
|
|
132
137
|
var linkCount = {{ (profile.attachments.length if profile.attachments) or 0 }};
|
|
133
138
|
document.getElementById('add-link-btn').addEventListener('click', function() {
|
|
134
139
|
linkCount++;
|
|
@@ -167,10 +172,9 @@
|
|
|
167
172
|
|
|
168
173
|
var removeBtn = document.createElement('button');
|
|
169
174
|
removeBtn.type = 'button';
|
|
170
|
-
removeBtn.className = 'button button--small';
|
|
175
|
+
removeBtn.className = 'button button--small profile-link-remove';
|
|
171
176
|
removeBtn.style.cssText = 'margin-block-end: 4px;';
|
|
172
177
|
removeBtn.textContent = 'Remove';
|
|
173
|
-
removeBtn.addEventListener('click', function() { row.remove(); });
|
|
174
178
|
|
|
175
179
|
row.appendChild(nameDiv);
|
|
176
180
|
row.appendChild(valueDiv);
|
|
@@ -47,8 +47,7 @@
|
|
|
47
47
|
:class="{ 'ap-lookup-autocomplete__item--highlighted': index === highlighted }"
|
|
48
48
|
@click="selectItem(item)"
|
|
49
49
|
@mouseenter="highlighted = index">
|
|
50
|
-
<img :src="item.avatar" :alt="item.name" class="ap-lookup-autocomplete__avatar"
|
|
51
|
-
onerror="this.style.display='none'">
|
|
50
|
+
<img :src="item.avatar" :alt="item.name" class="ap-lookup-autocomplete__avatar">
|
|
52
51
|
<span class="ap-lookup-autocomplete__info">
|
|
53
52
|
<span class="ap-lookup-autocomplete__name" x-text="item.name"></span>
|
|
54
53
|
<span class="ap-lookup-autocomplete__handle" x-text="item.handle"></span>
|
|
@@ -38,13 +38,11 @@
|
|
|
38
38
|
|
|
39
39
|
{# Profile info #}
|
|
40
40
|
<div class="ap-profile__info">
|
|
41
|
-
<div class="ap-profile__avatar-wrap">
|
|
41
|
+
<div class="ap-profile__avatar-wrap" data-avatar-fallback>
|
|
42
42
|
{% if icon %}
|
|
43
|
-
|
|
44
|
-
onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'ap-profile__avatar ap-profile__avatar--placeholder',textContent:'{{ name[0] }}'}))">
|
|
45
|
-
{% else %}
|
|
46
|
-
<div class="ap-profile__avatar ap-profile__avatar--placeholder">{{ name[0] }}</div>
|
|
43
|
+
<img src="{{ icon }}" alt="{{ name }}" class="ap-profile__avatar">
|
|
47
44
|
{% endif %}
|
|
45
|
+
<div class="ap-profile__avatar ap-profile__avatar--placeholder">{{ name[0] }}</div>
|
|
48
46
|
</div>
|
|
49
47
|
|
|
50
48
|
<div class="ap-profile__details">
|
|
@@ -10,8 +10,10 @@
|
|
|
10
10
|
{# Relative timestamps — converts absolute dates to "5m", "3h", "2d" etc. #}
|
|
11
11
|
<script defer src="/assets/@rmdes-indiekit-endpoint-activitypub/reader-relative-time.js"></script>
|
|
12
12
|
|
|
13
|
-
{#
|
|
14
|
-
<script
|
|
13
|
+
{# Avatar fallback — remove broken images to reveal initials fallback underneath #}
|
|
14
|
+
<script>document.addEventListener("error",function(e){var t=e.target;if(t.tagName==="IMG"&&t.closest("[data-avatar-fallback]"))t.remove()},true)</script>
|
|
15
|
+
|
|
16
|
+
{# Alpine.js loaded by default.njk — AP scripts register via alpine:init before it initializes #}
|
|
15
17
|
|
|
16
18
|
{# Reader stylesheet — loaded in body is fine for modern browsers #}
|
|
17
19
|
<link rel="stylesheet" href="/assets/@rmdes-indiekit-endpoint-activitypub/reader.css">
|
|
@@ -39,13 +39,12 @@
|
|
|
39
39
|
|
|
40
40
|
{# Author header #}
|
|
41
41
|
<header class="ap-card__author">
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
{% else %}
|
|
42
|
+
<div class="ap-card__avatar-wrap" data-avatar-fallback>
|
|
43
|
+
{% if item.author.photo %}
|
|
44
|
+
<img src="{{ item.author.photo }}" alt="{{ item.author.name }}" class="ap-card__avatar" loading="lazy" crossorigin="anonymous">
|
|
45
|
+
{% endif %}
|
|
47
46
|
<span class="ap-card__avatar ap-card__avatar--default" aria-hidden="true">{{ item.author.name[0] | upper if item.author.name else "?" }}</span>
|
|
48
|
-
|
|
47
|
+
</div>
|
|
49
48
|
<div class="ap-card__author-info">
|
|
50
49
|
<div class="ap-card__author-name">
|
|
51
50
|
{% if item.author.url %}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
{% set displayCount = item.photo.length if item.photo.length < 4 else 4 %}
|
|
6
6
|
{% set extraCount = item.photo.length - 4 %}
|
|
7
7
|
{% set totalPhotos = item.photo.length %}
|
|
8
|
-
<div x-data="{ lightbox: false, idx: 0 }" class="ap-card__gallery ap-card__gallery--{{ displayCount }}">
|
|
8
|
+
<div x-data="{ lightbox: false, idx: 0, touchX: 0 }" class="ap-card__gallery ap-card__gallery--{{ displayCount }}">
|
|
9
9
|
{% for photo in item.photo %}
|
|
10
10
|
{# Support both old string format and new object format #}
|
|
11
11
|
{% set photoSrc = photo.url if photo.url else photo %}
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
|
|
37
37
|
{# Lightbox modal — teleported to body to prevent overflow clipping #}
|
|
38
38
|
<template x-teleport="body">
|
|
39
|
-
<div x-show="lightbox" x-cloak @keydown.escape.window="lightbox = false" @click.self="lightbox = false" class="ap-lightbox" role="dialog" aria-modal="true">
|
|
39
|
+
<div x-show="lightbox" x-cloak @keydown.escape.window="lightbox = false" @click.self="lightbox = false" @touchstart="touchX = $event.changedTouches[0].clientX" @touchend="let dx = $event.changedTouches[0].clientX - touchX; if (dx < -50) idx = (idx + 1) % {{ totalPhotos }}; else if (dx > 50) idx = (idx - 1 + {{ totalPhotos }}) % {{ totalPhotos }}" class="ap-lightbox" role="dialog" aria-modal="true">
|
|
40
40
|
<button type="button" @click="lightbox = false" class="ap-lightbox__close" aria-label="Close">×</button>
|
|
41
41
|
{% if totalPhotos > 1 %}
|
|
42
42
|
<button type="button" @click="idx = (idx - 1 + {{ totalPhotos }}) % {{ totalPhotos }}" class="ap-lightbox__prev" aria-label="Previous image">‹</button>
|
|
@@ -9,14 +9,11 @@
|
|
|
9
9
|
</form>
|
|
10
10
|
|
|
11
11
|
{# Actor avatar with type badge #}
|
|
12
|
-
<div class="ap-notification__avatar-wrap">
|
|
12
|
+
<div class="ap-notification__avatar-wrap" data-avatar-fallback>
|
|
13
13
|
{% if item.actorPhoto %}
|
|
14
|
-
|
|
15
|
-
onerror="this.style.display='none';this.nextElementSibling.style.display=''">
|
|
16
|
-
<span class="ap-notification__avatar ap-notification__avatar--default" style="display:none" aria-hidden="true">{{ item.actorName[0] | upper if item.actorName else "?" }}</span>
|
|
17
|
-
{% else %}
|
|
18
|
-
<span class="ap-notification__avatar ap-notification__avatar--default" aria-hidden="true">{{ item.actorName[0] | upper if item.actorName else "?" }}</span>
|
|
14
|
+
<img src="{{ item.actorPhoto }}" alt="{{ item.actorName }}" class="ap-notification__avatar" loading="lazy" crossorigin="anonymous">
|
|
19
15
|
{% endif %}
|
|
16
|
+
<span class="ap-notification__avatar ap-notification__avatar--default" aria-hidden="true">{{ item.actorName[0] | upper if item.actorName else "?" }}</span>
|
|
20
17
|
<span class="ap-notification__type-badge">
|
|
21
18
|
{% if item.type == "like" %}❤{% elif item.type == "boost" %}🔁{% elif item.type == "follow" %}👤{% elif item.type == "reply" %}💬{% elif item.type == "mention" %}@{% endif %}
|
|
22
19
|
</span>
|