+5
deno.lock
+5
deno.lock
···
8
8
"npm:@tsconfig/svelte@^5.0.4": "5.0.4",
9
9
"npm:moment@^2.30.1": "2.30.1",
10
10
"npm:svelte-check@^4.1.5": "4.1.6_svelte@5.28.1__acorn@8.14.1_typescript@5.7.3",
11
+
"npm:svelte-infinite-loading@^1.4.0": "1.4.0",
11
12
"npm:svelte@^5.23.1": "5.28.1_acorn@8.14.1",
12
13
"npm:typescript@~5.7.2": "5.7.3",
13
14
"npm:vite@^6.3.1": "6.3.2_picomatch@4.0.2"
···
415
416
"typescript"
416
417
]
417
418
},
419
+
"svelte-infinite-loading@1.4.0": {
420
+
"integrity": "sha512-Jo+f/yr/HmZQuIiiKKzAHVFXdAUWHW2RBbrcQTil8JVk1sCm/riy7KTJVzjBgQvHasrFQYKF84zvtc9/Y4lFYg=="
421
+
},
418
422
"svelte@5.28.1_acorn@8.14.1": {
419
423
"integrity": "sha512-iOa9WmfNG95lSOSJdMhdjJ4Afok7IRAQYXpbnxhd5EINnXseG0GVa9j6WPght4eX78XfFez45Fi+uRglGKPV/Q==",
420
424
"dependencies": [
···
476
480
"npm:@tsconfig/svelte@^5.0.4",
477
481
"npm:moment@^2.30.1",
478
482
"npm:svelte-check@^4.1.5",
483
+
"npm:svelte-infinite-loading@^1.4.0",
479
484
"npm:svelte@^5.23.1",
480
485
"npm:typescript@~5.7.2",
481
486
"npm:vite@^6.3.1"
+2
-1
package.json
+2
-1
package.json
+36
-16
src/App.svelte
+36
-16
src/App.svelte
···
1
1
<script lang="ts">
2
2
import PostComponent from "./lib/PostComponent.svelte";
3
3
import AccountComponent from "./lib/AccountComponent.svelte";
4
+
import InfiniteLoading from "svelte-infinite-loading";
4
5
import { getNextPosts, Post, getAllMetadataFromPds } from "./lib/pdsfetch";
5
6
import { Config } from "../config";
6
-
const postsPromise = getNextPosts();
7
7
const accountsPromise = getAllMetadataFromPds();
8
+
import { onMount } from "svelte";
9
+
10
+
let posts: Post[] = [];
11
+
12
+
onMount(() => {
13
+
// Fetch initial posts
14
+
getNextPosts().then((initialPosts) => {
15
+
posts = initialPosts;
16
+
});
17
+
});
18
+
// Infinite loading function
19
+
const onInfinite = ({ detail: { loaded, complete } }) => {
20
+
getNextPosts().then((newPosts) => {
21
+
if (newPosts.length > 0) {
22
+
posts = [...posts, ...newPosts];
23
+
loaded();
24
+
} else {
25
+
complete();
26
+
}
27
+
});
28
+
};
8
29
</script>
9
30
10
31
<main>
···
12
33
{#await accountsPromise}
13
34
<p>Loading...</p>
14
35
{:then accountsData}
15
-
16
36
<div id="Account">
17
37
<h1 id="Header">ATProto PDS</h1>
18
38
<p>Home to {accountsData.length} accounts</p>
···
27
47
<p>Error: {error.message}</p>
28
48
{/await}
29
49
30
-
{#await postsPromise}
31
-
<p>Loading...</p>
32
-
{:then postsData}
33
-
<button on:click={getNextPosts}>
34
-
Load more posts
35
-
</button>
36
-
<div id="Feed">
37
-
<div id="spacer"></div>
38
-
{#each postsData as postObject}
39
-
<PostComponent post={postObject as Post} />
40
-
{/each}
41
-
<div id="spacer"></div>
42
-
</div>
43
-
{/await}
50
+
<div id="Feed">
51
+
<div id="spacer"></div>
52
+
{#each posts as postObject}
53
+
<PostComponent post={postObject as Post} />
54
+
{/each}
55
+
<InfiniteLoading on:infinite={onInfinite}
56
+
id="infiniteLoading"
57
+
distance={0}
58
+
threshold={0}
59
+
useWindow={false}
60
+
forceUseWindow={false}
61
+
/>
62
+
<div id="spacer"></div>
63
+
</div>
44
64
</div>
45
65
</main>
46
66
+29
-20
src/lib/pdsfetch.ts
+29
-20
src/lib/pdsfetch.ts
···
26
26
}
27
27
28
28
let accountsMetadata: AccountMetadata[] = [];
29
-
// a chronologically sorted list of posts for all users, that will be shown by svelte
30
-
// getNextPosts will populate this list with additional posts as needed
31
-
let posts: Post[] = [];
29
+
32
30
interface atUriObject {
33
31
repo: string;
34
32
collection: string;
···
259
257
return postDate >= cutoffDate;
260
258
});
261
259
if (filtered.length > 0) {
262
-
postAcc.account.currentCursor = filtered[filtered.length - 1].cid;
260
+
postAcc.account.currentCursor = processAtUri(filtered[filtered.length - 1].uri).rkey;
263
261
}
264
262
return {
265
263
posts: filtered,
···
298
296
const cutoffDate = getCutoffDate(recordsFiltered);
299
297
const recordsCutoff = filterPostsByDate(recordsFiltered, cutoffDate);
300
298
// update the accountMetadata with the new cursor
301
-
accountsMetadata = recordsCutoff.map((postAcc) => postAcc.account);
299
+
accountsMetadata = accountsMetadata.map((account) => {
300
+
const postAcc = recordsCutoff.find(
301
+
(postAcc) => postAcc.account.did == account.did,
302
+
);
303
+
if (postAcc) {
304
+
account.currentCursor = postAcc.account.currentCursor;
305
+
}
306
+
return account;
307
+
}
308
+
);
302
309
// throw the records in a big single array
303
310
let records = recordsCutoff.flatMap((postAcc) => postAcc.posts);
304
311
// sort the records by timestamp
···
310
317
(b.value as AppBskyFeedPost.Record).createdAt,
311
318
).getTime();
312
319
return bDate - aDate;
313
-
}
314
-
);
320
+
});
315
321
// filter out posts that are in the future
316
322
if (!Config.SHOW_FUTURE_POSTS) {
317
323
const now = Date.now();
···
323
329
});
324
330
}
325
331
// append the new posts to the existing posts
326
-
posts = posts.concat(
327
-
records.map((record) => {
328
-
const account = accountsMetadata.find(
329
-
(account) => account.did == processAtUri(record.uri).repo,
332
+
333
+
const newPosts = records.map((record) => {
334
+
const account = accountsMetadata.find(
335
+
(account) => account.did == processAtUri(record.uri).repo,
336
+
);
337
+
if (!account) {
338
+
throw new Error(
339
+
`Account with DID ${processAtUri(record.uri).repo} not found`,
330
340
);
331
-
if (!account) {
332
-
throw new Error(`Account with DID ${processAtUri(record.uri).repo} not found`);
333
-
}
334
-
return new Post(record, account);
335
-
}),
336
-
);
337
-
console.log("Fetched posts:", posts);
338
-
return posts;
341
+
}
342
+
return new Post(record, account);
343
+
});
344
+
console.log("Fetched posts:", newPosts);
345
+
console.log("Metadata:", accountsMetadata);
346
+
return newPosts;
339
347
};
340
348
341
349
const fetchPostsForUser = async (did: At.Did, cursor: string | null) => {
342
350
try {
351
+
console.log("Fetching posts for user:", did, "with Cursor: ", cursor);
343
352
const { data } = await rpc.get("com.atproto.repo.listRecords", {
344
353
params: {
345
354
repo: did as At.Identifier,
···
388
397
389
398
// return posts.slice(0, Config.MAX_POSTS);
390
399
// };
391
-
export { getAllMetadataFromPds, getNextPosts, Post, posts };
400
+
export { getAllMetadataFromPds, getNextPosts, Post };
392
401
export type { AccountMetadata };