pds dash for shimaenaga.veryroundbird.house (based off of pds.witchcraft.systems)
1<script lang="ts">
2 import { Post } from "./pdsfetch";
3 import { Config } from "../../config";
4 import { onMount } from "svelte";
5 import moment from "moment";
6
7 let { post }: { post: Post } = $props();
8
9 // State for image carousel
10 let currentImageIndex = $state(0);
11
12 // Functions to navigate carousel
13 function nextImage() {
14 if (post.imagesCid && currentImageIndex < post.imagesCid.length - 1) {
15 currentImageIndex++;
16 }
17 }
18
19 function prevImage() {
20 if (currentImageIndex > 0) {
21 currentImageIndex--;
22 }
23 }
24
25 // Function to preload an image
26 function preloadImage(index: number): void {
27 if (!post.imagesCid || index < 0 || index >= post.imagesCid.length) return;
28
29 const img = new Image();
30 img.src = `${Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did=${post.authorDid}&cid=${post.imagesCid[index]}`;
31 }
32
33 // Preload adjacent images when current index changes
34 $effect(() => {
35 if (post.imagesCid && post.imagesCid.length > 1) {
36 // Preload next image if available
37 if (currentImageIndex < post.imagesCid.length - 1) {
38 preloadImage(currentImageIndex + 1);
39 }
40
41 // Preload previous image if available
42 if (currentImageIndex > 0) {
43 preloadImage(currentImageIndex - 1);
44 }
45 }
46 });
47
48 // Initial preload of images
49 onMount(() => {
50 if (post.imagesCid && post.imagesCid.length > 1) {
51 // Preload the next image if it exists
52 if (post.imagesCid.length > 1) {
53 preloadImage(1);
54 }
55 }
56 });
57</script>
58
59<div class="postContainer">
60 <div class="postHeader">
61 {#if post.authorAvatarCid}
62 <img
63 class="avatar"
64 src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={post.authorAvatarCid}"
65 alt="avatar of {post.displayName}"
66 />
67 {/if}
68 <div class="headerText">
69 <a class="displayName" href="{Config.FRONTEND_URL}/profile/{post.authorDid}"
70 >{post.displayName}</a
71 >
72 <p class="handle">
73 <a href="{Config.FRONTEND_URL}/profile/{post.authorHandle}"
74 >@{post.authorHandle}</a
75 >
76
77 <a
78 class="postLink"
79 href="{Config.FRONTEND_URL}/profile/{post.authorDid}/post/{post.recordName}"
80 >{moment(post.timenotstamp).isBefore(moment().subtract(1, "month"))
81 ? moment(post.timenotstamp).format("MMM D, YYYY")
82 : moment(post.timenotstamp).fromNow()}</a
83 >
84 </p>
85 </div>
86 </div>
87 <div class="postContent">
88 {#if post.replyingUri}
89 <a
90 class="replyingText"
91 href="{Config.FRONTEND_URL}/profile/{post.replyingUri.repo}/post/{post
92 .replyingUri.rkey}">replying to {post.replyingUri.repo}</a
93 >
94 {/if}
95 {#if post.quotingUri}
96 <a
97 class="quotingText"
98 href="{Config.FRONTEND_URL}/profile/{post.quotingUri.repo}/post/{post
99 .quotingUri.rkey}">quoting {post.quotingUri.repo}</a
100 >
101 {/if}
102 <div class="postText">{post.text}</div>
103 {#if post.imagesCid && post.imagesCid.length > 0}
104 <div id="carouselContainer">
105 <img
106 class="embedImages"
107 alt="Post Image {currentImageIndex + 1} of {post.imagesCid.length}"
108 src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={post
109 .imagesCid[currentImageIndex]}"
110 />
111
112 {#if post.imagesCid.length > 1}
113 <div class="carouselControls">
114 <button
115 id="prevBtn"
116 onclick={prevImage}
117 disabled={currentImageIndex === 0}>←</button
118 >
119 <div class="carouselIndicators">
120 {#each post.imagesCid as _, i}
121 <div
122 class="indicator {i === currentImageIndex ? 'active' : ''}"
123 ></div>
124 {/each}
125 </div>
126 <button
127 class="nextBtn"
128 onclick={nextImage}
129 disabled={currentImageIndex === post.imagesCid.length - 1}
130 >→</button
131 >
132 </div>
133 {/if}
134 </div>
135 {/if}
136 {#if post.videosLinkCid}
137 <!-- svelte-ignore a11y_media_has_caption -->
138 <video
139 class="embedVideo"
140 src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={post.videosLinkCid}"
141 controls
142 ></video>
143 {/if}
144 {#if post.gifLink}
145 <img
146 class="embedVideo"
147 src="{post.gifLink}"
148 alt="Post GIF"
149 />
150 {/if}
151 </div>
152</div>
153
154<style>
155
156</style>