+37
-56
src/mixins/post.pug
+37
-56
src/mixins/post.pug
···
28
28
| ·
29
29
a(href=`/comments/${p.id}?from=${from}&sort=${sortQuery}&view=${viewQuery}`) #{fmtnum (p.num_comments)} ↩
30
30
if (query.view == "card" && !isPostGallery(p) && !isPostImage(p) && !isPostVideo(p) && p.selftext_html)
31
-
div.self-text-overflow(class='card')
32
-
if query.view == "card" && (p.spoiler || p.over_18)
31
+
div.self-text-overflow.card
32
+
if p.spoiler || p.over_18
33
33
div.spoiler(id=`spoiler_${p.id}`, onclick=`javascript:document.getElementById('spoiler_${p.id}').style.display = 'none';`)
34
34
h2
35
35
!= p.over_18 ? 'nsfw' : 'spoiler'
36
-
div.self-text(class='card')
36
+
div.self-text.card
37
37
!= convertInlineImageLinks(p.selftext_html)
38
-
div.media-preview(class=`${query.view}`)
39
-
- var onclick = query.view != "card" ? `toggleDetails('${p.id}')` : ``
38
+
if query.view != "card"
39
+
div.media-preview
40
+
- var onclick = `toggleDetails('${p.id}')`
41
+
if isPostGallery(p)
42
+
- var item = (p.over_18 ? `/nsfw.svg` : p.spoiler ? `/spoiler.svg` : postGalleryItems(p)[0].url)
43
+
img(src=item onclick=onclick)
44
+
else if isPostImage(p)
45
+
- var url = postThumbnail(p)
46
+
img(src=url onclick=onclick)
47
+
else if isPostVideo(p)
48
+
- var decodedVideos = decodePostVideoUrls(p)
49
+
video(autoplay="" muted="" data-dashjs-player="" onclick=`toggleDetails('${p.id}')` poster=decodedVideos[4] width="100px" height="100px")
50
+
// Scrubber
51
+
source(src=decodedVideos[3])
52
+
else if isPostLink(p)
53
+
a(href=p.url)
54
+
| ↗
55
+
56
+
details(id=`${p.id}` open=(query.view == "card" && (isPostGallery(p) || isPostImage(p) || isPostVideo(p))))
57
+
summary.expand-post expand media
58
+
div.image-viewer
40
59
if query.view == "card" && (p.spoiler || p.over_18) && (isPostGallery(p) || isPostImage(p) || isPostVideo(p))
41
60
div.spoiler(id=`spoiler_${p.id}`, onclick=`javascript:document.getElementById('spoiler_${p.id}').style.display = 'none';`)
42
61
h2
43
62
!= p.over_18 ? 'nsfw' : 'spoiler'
44
63
if isPostGallery(p)
45
-
- var item = postGalleryItems(p)[0]
46
-
if query.view == "card"
47
-
div.gallery(class=`${query.view}`)
48
-
each item in postGalleryItems(p)
49
-
div.gallery-item(class=`${query.view}`)
50
-
a(href=`/media/${item.url}`)
51
-
img(src=item.url loading="lazy")
52
-
div.gallery-item-idx(class=`${query.view}`)
53
-
| #{`${item.idx}/${item.total}`}
54
-
else
55
-
img(src=item.url onclick=onclick)
64
+
div.gallery
65
+
each item in postGalleryItems(p)
66
+
div.gallery-item
67
+
a(href=`/media/${item.url}`)
68
+
img(src=item.url loading="lazy")
69
+
div.gallery-item-idx
70
+
| #{`${item.idx}/${item.total}`}
56
71
else if isPostImage(p)
57
-
- var url = query.view == "card" ? p.url : postThumbnail(p)
58
-
#{query.view == "card" ? "a href=/media/" + url : span}
59
-
img(src=url onclick=onclick)
72
+
a(href=`/media/${p.url}`)
73
+
img(src=p.url loading="lazy")
60
74
else if isPostVideo(p)
61
75
- var decodedVideos = decodePostVideoUrls(p)
62
-
if query.view == "card"
63
-
video(controls="" muted="" data-dashjs-player="" preload="metadata" poster=decodedVideos[4])
76
+
video(controls="" muted="" data-dashjs-player="" preload="metadata" playsinline="" poster=decodedVideos[4] objectfit="contain" loading="lazy")
64
77
// HLS
65
78
source(src=decodedVideos[0])
66
79
// Dash
67
80
source(src=decodedVideos[1])
68
81
// Fallback
69
82
source(src=decodedVideos[2])
70
-
else
71
-
video(autoplay="" muted="" data-dashjs-player="" onclick=`toggleDetails('${p.id}')` width="100px" height="100px")
72
-
// Scrubber
73
-
source(src=decodedVideos[3])
74
-
else if isPostLink(p)
75
-
a(href=p.url)
76
-
if (query.view == 'card')
77
-
| #{p.domain}
78
-
| ↗
79
-
80
-
if query.view == "compact" && (isPostGallery(p) || isPostImage(p) || isPostVideo(p))
81
-
details(id=`${p.id}`)
82
-
summary.expand-post expand media
83
-
div.image-viewer
84
-
if isPostGallery(p)
85
-
div.gallery
86
-
each item in postGalleryItems(p)
87
-
div.gallery-item
88
-
div.gallery-item-idx
89
-
| #{`${item.idx}/${item.total}`}
90
-
a(href=`/media/${item.url}`)
91
-
img(src=item.url loading="lazy")
92
-
else if isPostImage(p)
93
-
a(href=`/media/${p.url}`)
94
-
img(src=p.url loading="lazy").post-media
95
-
else if isPostVideo(p)
96
-
video(controls="" muted="" data-dashjs-player="" preload="metadata" playsinline="" poster=decodedVideos[4] objectfit="contain" loading="lazy").post-media
97
-
//HLS
98
-
source(src=decodedVideos[0])
99
-
// Dash
100
-
source(src=decodedVideos[1])
101
-
// Fallback
102
-
source(src=decodedVideos[2])
103
-
button(onclick=`toggleDetails('${p.id}')`)
104
-
| close
83
+
if (query.view == "compact")
84
+
button(onclick=`toggleDetails('${p.id}')`)
85
+
| close
+32
-38
src/public/styles.css
+32
-38
src/public/styles.css
···
11
11
--link-visited-color: #999;
12
12
--accent: var(--link-color);
13
13
--error-text-color: red;
14
+
--border-radius-card: 8px;
15
+
--border-radius-media: 6px;
16
+
--border-radius-preview: 4px;
14
17
15
18
font-family: Inter, sans-serif;
16
19
font-feature-settings: 'ss01' 1, 'kern' 1, 'liga' 1, 'cv05' 1, 'dlig' 1, 'ss01' 1, 'ss07' 1, 'ss08' 1;
···
45
48
overflow-x: hidden;
46
49
background-color: var(--bg-color);
47
50
color: var(--text-color);
48
-
}
49
-
50
-
body:has(details.card[open]) {
51
-
overflow: hidden;
52
51
}
53
52
54
53
body.media-maximized {
···
169
168
170
169
.post-container.card {
171
170
border: 1px solid var(--bg-color-muted);
172
-
border-radius: 8px;
171
+
border-radius: var(--border-radius-card);
173
172
display: block;
174
173
}
175
174
···
198
197
text-overflow: ellipsis;
199
198
}
200
199
201
-
.media-preview.card {
200
+
.image-viewer {
202
201
position: relative;
203
202
padding: 0.3rem;
204
203
padding-bottom: 0.3rem;
205
204
}
206
205
207
-
.media-preview.card > img {
206
+
.image-viewer > img {
208
207
cursor: pointer;
209
208
}
210
209
211
-
.gallery.card {
212
-
align-items: center;
213
-
scroll-snap-type: both mandatory;
214
-
}
215
-
216
-
.gallery-item.card {
217
-
max-width: 100%;
218
-
width: 100%;
219
-
scroll-snap-align: center;
220
-
}
221
-
222
-
.gallery-item-idx.card {
223
-
text-align: center;
224
-
}
225
-
226
210
.spoiler {
227
211
background-color: rbga(var(--bg-color-muted), 0.2);
228
212
/* Safari on iOS <= 17 */
229
213
-webkit-backdrop-filter: blur(3rem);
230
214
backdrop-filter: blur(3rem);
231
-
border-radius: 4px;
215
+
border-radius: var(--border-radius-preview);
232
216
233
217
position: absolute;
234
218
top: 0;
···
247
231
z-index: 10;
248
232
}
249
233
250
-
.gallery-item-idx.card,
234
+
.gallery-item-idx,
251
235
.spoiler > h2 {
252
236
text-shadow: 0.1rem 0.1rem 1rem var(--bg-color-muted);
253
237
}
···
294
278
object-fit: cover;
295
279
width: 4rem;
296
280
height: 4rem;
281
+
border-radius: var(--border-radius-preview);
297
282
}
298
283
299
-
.media-preview.card {
284
+
.image-viewer {
300
285
padding: unset;
301
286
}
302
287
303
-
.media-preview.card img,
304
-
.media-preview.card video {
305
-
border-radius: 6px;
288
+
.image-viewer img,
289
+
.image-viewer video {
290
+
border-radius: var(--border-radius-media);
306
291
307
292
max-height: 40vh;
308
293
max-width: 95%;
···
317
302
object-fit: fill;
318
303
}
319
304
320
-
.media-preview.card a {
305
+
.image-viewer a {
321
306
font-size: 1.5rem;
322
307
padding: unset;
323
308
padding-left: 1rem;
324
309
}
325
310
326
-
.media-preview.card a:has(img) {
311
+
.image-viewer a:has(img) {
327
312
font-size: 0rem;
328
313
padding: unset;
329
314
}
···
382
367
width: 5rem;
383
368
height: 5rem;
384
369
}
385
-
.media-preview.card img,
386
-
.media-preview.card video
370
+
.image-viewer img,
371
+
.image-viewer video
387
372
{
388
373
max-height: 50vh;
389
374
}
390
-
.media-preview.card a {
375
+
.image-viewer a {
391
376
font-size: 1rem;
392
377
margin: 0.7rem;
393
378
padding: initial;
···
424
409
width: 5rem;
425
410
height: 5rem;
426
411
}
427
-
.media-preview.card img,
428
-
.media-preview.card video
412
+
.image-viewer img,
413
+
.image-viewer video
429
414
{
430
415
max-height: 30vh;
431
416
}
···
433
418
font-size: 2rem;
434
419
padding: 2rem;
435
420
}
436
-
.media-preview.card a {
421
+
.image-viewer a {
437
422
font-size: 1rem;
438
423
margin: 0.5rem;
439
424
padding: initial;
···
464
449
flex: 1 1 40%;
465
450
width: 40%;
466
451
}
467
-
.media-preview.card img,
468
-
.media-preview.card video
452
+
.image-viewer img,
453
+
.image-viewer video
469
454
{
470
455
max-height: 20vh;
471
456
}
···
648
633
overflow-x: auto;
649
634
position: relative;
650
635
padding: 5px;
636
+
align-items: center;
637
+
scroll-snap-type: both mandatory;
651
638
}
652
639
653
640
.gallery-item {
654
641
flex: 0 0 auto;
655
642
margin-right: 10px;
643
+
max-width: 100%;
644
+
width: 100%;
645
+
scroll-snap-align: center;
646
+
}
647
+
648
+
.gallery-item-idx {
649
+
text-align: center;
656
650
}
657
651
658
652
.gallery img {