replies timeline only, appview-less bluesky client

docs: add some todos in code

Changed files
+6 -14
src
routes
+6 -14
src/routes/+page.svelte
··· 221 // eslint-disable-next-line svelte/prefer-svelte-reactivity 222 const threadMap = new Map<ResourceUri, ThreadPost[]>(); 223 224 - // Single pass: create posts and group by thread 225 for (const [, timeline] of timelines) { 226 for (const [uri, data] of timeline) { 227 const parsedUri = expect(parseCanonicalResourceUri(uri)); ··· 250 // eslint-disable-next-line svelte/prefer-svelte-reactivity 251 const childrenMap = new Map<ResourceUri | null, ThreadPost[]>(); 252 253 - // Calculate depth and group by parent 254 for (const post of posts) { 255 let depth = 0; 256 let currentUri = post.parentUri; ··· 266 childrenMap.get(post.parentUri)!.push(post); 267 } 268 269 - // Sort children by time (newest first) 270 childrenMap 271 .values() 272 .forEach((children) => children.sort((a, b) => b.newestTime - a.newestTime)); 273 274 - // Helper to create a thread from posts 275 const createThread = ( 276 posts: ThreadPost[], 277 rootUri: ResourceUri, ··· 285 }; 286 }; 287 288 - // Helper to collect all posts in a subtree 289 const collectSubtree = (startPost: ThreadPost): ThreadPost[] => { 290 const result: ThreadPost[] = []; 291 const addWithChildren = (post: ThreadPost) => { ··· 297 return result; 298 }; 299 300 - // Find branching points (posts with 2+ children) 301 const branchingPoints = Array.from(childrenMap.entries()) 302 .filter(([, children]) => children.length > 1) 303 .map(([uri]) => uri); 304 305 if (branchingPoints.length === 0) { 306 - // No branches - single thread 307 const roots = childrenMap.get(null) || []; 308 const allPosts = roots.flatMap((root) => collectSubtree(root)); 309 threads.push(createThread(allPosts, rootUri)); 310 } else { 311 - // Has branches - split into separate threads 312 for (const branchParentUri of branchingPoints) { 313 const branches = childrenMap.get(branchParentUri) || []; 314 315 - // Sort branches oldest to newest for processing 316 const sortedBranches = [...branches].sort((a, b) => a.newestTime - b.newestTime); 317 318 sortedBranches.forEach((branchRoot, index) => { 319 const isOldestBranch = index === 0; 320 const branchPosts: ThreadPost[] = []; 321 322 - // If oldest branch, include parent chain 323 if (isOldestBranch && branchParentUri !== null) { 324 const parentChain: ThreadPost[] = []; 325 let currentUri: ResourceUri | null = branchParentUri; ··· 330 branchPosts.push(...parentChain); 331 } 332 333 - // Add branch posts 334 branchPosts.push(...collectSubtree(branchRoot)); 335 336 - // Recalculate depths for display 337 const minDepth = Math.min(...branchPosts.map((p) => p.depth)); 338 branchPosts.forEach((p) => (p.depth = p.depth - minDepth)); 339 ··· 349 } 350 } 351 352 - // Sort threads by newest time (descending) so older branches appear first 353 threads.sort((a, b) => b.newestTime - a.newestTime); 354 355 // console.log(threads); ··· 357 return threads; 358 }; 359 360 - // Filtering functions 361 const isOwnPost = (post: ThreadPost, accounts: Account[]) => 362 accounts.some((account) => account.did === post.did); 363 const hasNonOwnPost = (posts: ThreadPost[], accounts: Account[]) =>
··· 221 // eslint-disable-next-line svelte/prefer-svelte-reactivity 222 const threadMap = new Map<ResourceUri, ThreadPost[]>(); 223 224 + // group posts by root uri into "thread" chains 225 for (const [, timeline] of timelines) { 226 for (const [uri, data] of timeline) { 227 const parsedUri = expect(parseCanonicalResourceUri(uri)); ··· 250 // eslint-disable-next-line svelte/prefer-svelte-reactivity 251 const childrenMap = new Map<ResourceUri | null, ThreadPost[]>(); 252 253 + // calculate depths 254 for (const post of posts) { 255 let depth = 0; 256 let currentUri = post.parentUri; ··· 266 childrenMap.get(post.parentUri)!.push(post); 267 } 268 269 childrenMap 270 .values() 271 .forEach((children) => children.sort((a, b) => b.newestTime - a.newestTime)); 272 273 const createThread = ( 274 posts: ThreadPost[], 275 rootUri: ResourceUri, ··· 283 }; 284 }; 285 286 const collectSubtree = (startPost: ThreadPost): ThreadPost[] => { 287 const result: ThreadPost[] = []; 288 const addWithChildren = (post: ThreadPost) => { ··· 294 return result; 295 }; 296 297 + // find posts with >2 children to split them into separate chains 298 const branchingPoints = Array.from(childrenMap.entries()) 299 .filter(([, children]) => children.length > 1) 300 .map(([uri]) => uri); 301 302 if (branchingPoints.length === 0) { 303 const roots = childrenMap.get(null) || []; 304 const allPosts = roots.flatMap((root) => collectSubtree(root)); 305 threads.push(createThread(allPosts, rootUri)); 306 } else { 307 for (const branchParentUri of branchingPoints) { 308 const branches = childrenMap.get(branchParentUri) || []; 309 310 const sortedBranches = [...branches].sort((a, b) => a.newestTime - b.newestTime); 311 312 sortedBranches.forEach((branchRoot, index) => { 313 const isOldestBranch = index === 0; 314 const branchPosts: ThreadPost[] = []; 315 316 + // the oldest branch has the full context 317 + // todo: consider letting the user decide this..? 318 if (isOldestBranch && branchParentUri !== null) { 319 const parentChain: ThreadPost[] = []; 320 let currentUri: ResourceUri | null = branchParentUri; ··· 325 branchPosts.push(...parentChain); 326 } 327 328 branchPosts.push(...collectSubtree(branchRoot)); 329 330 const minDepth = Math.min(...branchPosts.map((p) => p.depth)); 331 branchPosts.forEach((p) => (p.depth = p.depth - minDepth)); 332 ··· 342 } 343 } 344 345 threads.sort((a, b) => b.newestTime - a.newestTime); 346 347 // console.log(threads); ··· 349 return threads; 350 }; 351 352 + // todo: add more filtering options 353 const isOwnPost = (post: ThreadPost, accounts: Account[]) => 354 accounts.some((account) => account.did === post.did); 355 const hasNonOwnPost = (posts: ThreadPost[], accounts: Account[]) =>