chore: added unread -> read in post lists bd9a2404
Steve · 2025-11-01 22:34 3 file(s) · +64 −18
src/components/app-sidebar.tsx +59 −18
37 37
	allFeedsQuery,
38 38
	allPostsQuery,
39 39
	postsByFeedQuery,
40 +
	allReadStatusesQuery,
40 41
	useEvolu,
41 42
	reset,
42 43
} from "@/lib/evolu";
79 80
80 81
	const { insert, update } = useEvolu();
81 82
	const allFeeds = useQuery(allFeedsQuery);
83 +
	const allReadStatuses = useQuery(allReadStatusesQuery);
82 84
83 85
	// Get posts based on selected feed
84 86
	const allPosts = useQuery(allPostsQuery);
102 104
			return b.publishedDate.localeCompare(a.publishedDate);
103 105
		});
104 106
	}, [feedPosts, searchQuery]);
107 +
108 +
	// Check if a post is read
109 +
	const isPostRead = React.useCallback(
110 +
		(postId: string) => {
111 +
			return allReadStatuses.some((status) => status.postId === postId);
112 +
		},
113 +
		[allReadStatuses],
114 +
	);
115 +
116 +
	// Handle post selection and mark as read
117 +
	const handlePostSelect = React.useCallback(
118 +
		(postId: string) => {
119 +
			// Mark as read if not already read
120 +
			if (!isPostRead(postId)) {
121 +
				const post = feedPosts.find((p) => p.id === postId);
122 +
				if (post) {
123 +
					insert("readStatus", {
124 +
						postId: postId as any,
125 +
						feedId: post.feedId,
126 +
					});
127 +
				}
128 +
			}
129 +
			// Call the original onPostSelect
130 +
			onPostSelect(postId);
131 +
		},
132 +
		[isPostRead, feedPosts, insert, onPostSelect],
133 +
	);
105 134
106 135
	async function addFeed() {
107 136
		if (!urlInput.trim()) {
377 406
							No posts found
378 407
						</div>
379 408
					) : (
380 -
						filteredPosts.map((post) => (
381 -
							<button
382 -
								key={post.id}
383 -
								onClick={() => onPostSelect(post.id)}
384 -
								className={`hover:bg-sidebar-accent flex flex-col items-start gap-1.5 border-b px-3 py-3 text-sm text-left w-full last:border-b-0 transition-colors ${
385 -
									selectedPostId === post.id ? "bg-sidebar-accent" : ""
386 -
								}`}
387 -
							>
388 -
								<span className="font-medium line-clamp-2 leading-snug">
389 -
									{post.title}
390 -
								</span>
391 -
								{post.author && (
392 -
									<span className="text-muted-foreground text-xs">
393 -
										{post.author}
394 -
									</span>
395 -
								)}
396 -
							</button>
397 -
						))
409 +
						filteredPosts.map((post) => {
410 +
							const isRead = isPostRead(post.id);
411 +
							return (
412 +
								<button
413 +
									key={post.id}
414 +
									onClick={() => handlePostSelect(post.id)}
415 +
									className={`hover:bg-sidebar-accent flex items-start gap-2 border-b px-3 py-3 text-sm text-left w-full last:border-b-0 transition-colors ${
416 +
										selectedPostId === post.id ? "bg-sidebar-accent" : ""
417 +
									}`}
418 +
								>
419 +
									{/* Unread indicator */}
420 +
									<div className="flex-shrink-0 pt-1">
421 +
										{!isRead && (
422 +
											<div className="size-2 rounded-full bg-primary" />
423 +
										)}
424 +
									</div>
425 +
									{/* Post content */}
426 +
									<div className="flex flex-col gap-1.5 flex-1 min-w-0">
427 +
										<span className="font-medium line-clamp-2 leading-snug">
428 +
											{post.title}
429 +
										</span>
430 +
										{post.author && (
431 +
											<span className="text-muted-foreground text-xs">
432 +
												{post.author}
433 +
											</span>
434 +
										)}
435 +
									</div>
436 +
								</button>
437 +
							);
438 +
						})
398 439
					)}
399 440
				</div>
400 441
			</div>
src/lib/evolu.ts +4 −0
32 32
	db.selectFrom("rssFeed").selectAll().orderBy("category", "asc"),
33 33
);
34 34
35 +
export const allReadStatusesQuery = evolu.createQuery((db) =>
36 +
	db.selectFrom("readStatus").selectAll().where("isDeleted", "is", null),
37 +
);
38 +
35 39
export function reset() {
36 40
	evolu.resetAppOwner();
37 41
}
src/lib/scheme.ts +1 −0
43 43
		id: id("ReadStatus"),
44 44
		feedId: RSSFeedId,
45 45
		postId: RSSPostId,
46 +
		isDeleted: nullOr(NonEmptyString),
46 47
	},
47 48
	userPreferences: {
48 49
		id: id("UserPreferences"),