ari/DynamicPageLoads #2
4 changed files with 72 additions and 37 deletions
5
deno.lock
generated
5
deno.lock
generated
|
@ -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"
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue