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