this repo has no description

Frontend works

ari.express f00e0638 6ca0a971

verified
Changed files
+72 -37
src
+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
··· 13 13 "@atcute/bluesky": "^2.0.2", 14 14 "@atcute/client": "^3.0.1", 15 15 "@atcute/identity-resolver": "^0.1.2", 16 - "moment": "^2.30.1" 16 + "moment": "^2.30.1", 17 + "svelte-infinite-loading": "^1.4.0" 17 18 }, 18 19 "devDependencies": { 19 20 "@sveltejs/vite-plugin-svelte": "^5.0.3",
+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
··· 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 };