ari/DynamicPageLoads #2

Merged
astra merged 6 commits from ari/DynamicPageLoads into main 2025-04-22 03:14:38 +00:00
4 changed files with 72 additions and 37 deletions
Showing only changes of commit f00e063861 - Show all commits

5
deno.lock generated
View file

@ -8,6 +8,7 @@
"npm:@tsconfig/svelte@^5.0.4": "5.0.4", "npm:@tsconfig/svelte@^5.0.4": "5.0.4",
"npm:moment@^2.30.1": "2.30.1", "npm:moment@^2.30.1": "2.30.1",
"npm:svelte-check@^4.1.5": "4.1.6_svelte@5.28.1__acorn@8.14.1_typescript@5.7.3", "npm:svelte-check@^4.1.5": "4.1.6_svelte@5.28.1__acorn@8.14.1_typescript@5.7.3",
"npm:svelte-infinite-loading@^1.4.0": "1.4.0",
"npm:svelte@^5.23.1": "5.28.1_acorn@8.14.1", "npm:svelte@^5.23.1": "5.28.1_acorn@8.14.1",
"npm:typescript@~5.7.2": "5.7.3", "npm:typescript@~5.7.2": "5.7.3",
"npm:vite@^6.3.1": "6.3.2_picomatch@4.0.2" "npm:vite@^6.3.1": "6.3.2_picomatch@4.0.2"
@ -415,6 +416,9 @@
"typescript" "typescript"
] ]
}, },
"svelte-infinite-loading@1.4.0": {
"integrity": "sha512-Jo+f/yr/HmZQuIiiKKzAHVFXdAUWHW2RBbrcQTil8JVk1sCm/riy7KTJVzjBgQvHasrFQYKF84zvtc9/Y4lFYg=="
},
"svelte@5.28.1_acorn@8.14.1": { "svelte@5.28.1_acorn@8.14.1": {
"integrity": "sha512-iOa9WmfNG95lSOSJdMhdjJ4Afok7IRAQYXpbnxhd5EINnXseG0GVa9j6WPght4eX78XfFez45Fi+uRglGKPV/Q==", "integrity": "sha512-iOa9WmfNG95lSOSJdMhdjJ4Afok7IRAQYXpbnxhd5EINnXseG0GVa9j6WPght4eX78XfFez45Fi+uRglGKPV/Q==",
"dependencies": [ "dependencies": [
@ -476,6 +480,7 @@
"npm:@tsconfig/svelte@^5.0.4", "npm:@tsconfig/svelte@^5.0.4",
"npm:moment@^2.30.1", "npm:moment@^2.30.1",
"npm:svelte-check@^4.1.5", "npm:svelte-check@^4.1.5",
"npm:svelte-infinite-loading@^1.4.0",
"npm:svelte@^5.23.1", "npm:svelte@^5.23.1",
"npm:typescript@~5.7.2", "npm:typescript@~5.7.2",
"npm:vite@^6.3.1" "npm:vite@^6.3.1"

View file

@ -13,7 +13,8 @@
"@atcute/bluesky": "^2.0.2", "@atcute/bluesky": "^2.0.2",
"@atcute/client": "^3.0.1", "@atcute/client": "^3.0.1",
"@atcute/identity-resolver": "^0.1.2", "@atcute/identity-resolver": "^0.1.2",
"moment": "^2.30.1" "moment": "^2.30.1",
"svelte-infinite-loading": "^1.4.0"
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/vite-plugin-svelte": "^5.0.3", "@sveltejs/vite-plugin-svelte": "^5.0.3",

View file

@ -1,10 +1,31 @@
<script lang="ts"> <script lang="ts">
import PostComponent from "./lib/PostComponent.svelte"; import PostComponent from "./lib/PostComponent.svelte";
import AccountComponent from "./lib/AccountComponent.svelte"; import AccountComponent from "./lib/AccountComponent.svelte";
import InfiniteLoading from "svelte-infinite-loading";
import { getNextPosts, Post, getAllMetadataFromPds } from "./lib/pdsfetch"; import { getNextPosts, Post, getAllMetadataFromPds } from "./lib/pdsfetch";
import { Config } from "../config"; import { Config } from "../config";
const postsPromise = getNextPosts();
const accountsPromise = getAllMetadataFromPds(); const accountsPromise = getAllMetadataFromPds();
import { onMount } from "svelte";
let posts: Post[] = [];
onMount(() => {
// Fetch initial posts
getNextPosts().then((initialPosts) => {
posts = initialPosts;
});
});
// Infinite loading function
const onInfinite = ({ detail: { loaded, complete } }) => {
getNextPosts().then((newPosts) => {
if (newPosts.length > 0) {
posts = [...posts, ...newPosts];
loaded();
} else {
complete();
}
});
};
</script> </script>
<main> <main>
@ -12,7 +33,6 @@
{#await accountsPromise} {#await accountsPromise}
<p>Loading...</p> <p>Loading...</p>
{:then accountsData} {:then accountsData}
<div id="Account"> <div id="Account">
<h1 id="Header">ATProto PDS</h1> <h1 id="Header">ATProto PDS</h1>
<p>Home to {accountsData.length} accounts</p> <p>Home to {accountsData.length} accounts</p>
@ -27,20 +47,20 @@
<p>Error: {error.message}</p> <p>Error: {error.message}</p>
{/await} {/await}
{#await postsPromise} <div id="Feed">
<p>Loading...</p> <div id="spacer"></div>
{:then postsData} {#each posts as postObject}
<button on:click={getNextPosts}> <PostComponent post={postObject as Post} />
Load more posts {/each}
</button> <InfiniteLoading on:infinite={onInfinite}
<div id="Feed"> id="infiniteLoading"
<div id="spacer"></div> distance={0}
{#each postsData as postObject} threshold={0}
<PostComponent post={postObject as Post} /> useWindow={false}
{/each} forceUseWindow={false}
<div id="spacer"></div> />
</div> <div id="spacer"></div>
{/await} </div>
</div> </div>
</main> </main>

View file

@ -26,9 +26,7 @@ interface AccountMetadata {
} }
let accountsMetadata: AccountMetadata[] = []; let accountsMetadata: AccountMetadata[] = [];
// a chronologically sorted list of posts for all users, that will be shown by svelte
// getNextPosts will populate this list with additional posts as needed
let posts: Post[] = [];
interface atUriObject { interface atUriObject {
repo: string; repo: string;
collection: string; collection: string;
@ -259,7 +257,7 @@ const filterPostsByDate = (posts: PostsAcc[], cutoffDate: Date) => {
return postDate >= cutoffDate; return postDate >= cutoffDate;
}); });
if (filtered.length > 0) { if (filtered.length > 0) {
postAcc.account.currentCursor = filtered[filtered.length - 1].cid; postAcc.account.currentCursor = processAtUri(filtered[filtered.length - 1].uri).rkey;
} }
return { return {
posts: filtered, posts: filtered,
@ -298,7 +296,16 @@ const getNextPosts = async () => {
const cutoffDate = getCutoffDate(recordsFiltered); const cutoffDate = getCutoffDate(recordsFiltered);
const recordsCutoff = filterPostsByDate(recordsFiltered, cutoffDate); const recordsCutoff = filterPostsByDate(recordsFiltered, cutoffDate);
// update the accountMetadata with the new cursor // update the accountMetadata with the new cursor
accountsMetadata = recordsCutoff.map((postAcc) => postAcc.account); accountsMetadata = accountsMetadata.map((account) => {
const postAcc = recordsCutoff.find(
(postAcc) => postAcc.account.did == account.did,
);
if (postAcc) {
account.currentCursor = postAcc.account.currentCursor;
}
return account;
}
);
// throw the records in a big single array // throw the records in a big single array
let records = recordsCutoff.flatMap((postAcc) => postAcc.posts); let records = recordsCutoff.flatMap((postAcc) => postAcc.posts);
// sort the records by timestamp // sort the records by timestamp
@ -310,8 +317,7 @@ const getNextPosts = async () => {
(b.value as AppBskyFeedPost.Record).createdAt, (b.value as AppBskyFeedPost.Record).createdAt,
).getTime(); ).getTime();
return bDate - aDate; return bDate - aDate;
} });
);
// filter out posts that are in the future // filter out posts that are in the future
if (!Config.SHOW_FUTURE_POSTS) { if (!Config.SHOW_FUTURE_POSTS) {
const now = Date.now(); const now = Date.now();
@ -323,23 +329,26 @@ const getNextPosts = async () => {
}); });
} }
// append the new posts to the existing posts // append the new posts to the existing posts
posts = posts.concat(
records.map((record) => { const newPosts = records.map((record) => {
const account = accountsMetadata.find( const account = accountsMetadata.find(
(account) => account.did == processAtUri(record.uri).repo, (account) => account.did == processAtUri(record.uri).repo,
);
if (!account) {
throw new Error(
`Account with DID ${processAtUri(record.uri).repo} not found`,
); );
if (!account) { }
throw new Error(`Account with DID ${processAtUri(record.uri).repo} not found`); return new Post(record, account);
} });
return new Post(record, account); console.log("Fetched posts:", newPosts);
}), console.log("Metadata:", accountsMetadata);
); return newPosts;
console.log("Fetched posts:", posts);
return posts;
}; };
const fetchPostsForUser = async (did: At.Did, cursor: string | null) => { const fetchPostsForUser = async (did: At.Did, cursor: string | null) => {
try { try {
console.log("Fetching posts for user:", did, "with Cursor: ", cursor);
const { data } = await rpc.get("com.atproto.repo.listRecords", { const { data } = await rpc.get("com.atproto.repo.listRecords", {
params: { params: {
repo: did as At.Identifier, repo: did as At.Identifier,
@ -388,5 +397,5 @@ const fetchPostsForUser = async (did: At.Did, cursor: string | null) => {
// return posts.slice(0, Config.MAX_POSTS); // return posts.slice(0, Config.MAX_POSTS);
// }; // };
export { getAllMetadataFromPds, getNextPosts, Post, posts }; export { getAllMetadataFromPds, getNextPosts, Post };
export type { AccountMetadata }; export type { AccountMetadata };