Merge pull request #6 from stevedylandev/chore/update-navigation
e5cc239b
chore: updated navigation
1 file(s) · +70 −2
chore: updated navigation
| 20 | 20 | import { |
|
| 21 | 21 | allFeedsQuery, |
|
| 22 | 22 | allPostsQuery, |
|
| 23 | + | postsByFeedQuery, |
|
| 23 | 24 | allReadStatusesQuery, |
|
| 24 | 25 | allReadStatusesWithUnreadQuery, |
|
| 25 | 26 | useEvolu, |
|
| 40 | 41 | const evolu = useEvolu(); |
|
| 41 | 42 | const allFeeds = useQuery(allFeedsQuery); |
|
| 42 | 43 | const allPosts = useQuery(allPostsQuery); |
|
| 44 | + | const feedPostsQuery = useQuery(postsByFeedQuery(selectedFeedId || "")); |
|
| 43 | 45 | const allReadStatuses = useQuery(allReadStatusesQuery); |
|
| 44 | 46 | const allReadStatusesWithUnread = useQuery(allReadStatusesWithUnreadQuery); |
|
| 45 | 47 | console.log(allPosts); |
|
| 46 | 48 | ||
| 49 | + | // Check if a post is read |
|
| 50 | + | const isPostRead = React.useCallback( |
|
| 51 | + | (postId: string) => { |
|
| 52 | + | return allReadStatuses.some((status) => status.postId === postId); |
|
| 53 | + | }, |
|
| 54 | + | [allReadStatuses], |
|
| 55 | + | ); |
|
| 56 | + | ||
| 47 | 57 | // Get the first post (most recent) to use as default |
|
| 48 | 58 | const firstPostId = React.useMemo(() => { |
|
| 49 | 59 | if (allPosts.length === 0) return null; |
|
| 77 | 87 | ||
| 78 | 88 | // Get sorted posts for navigation |
|
| 79 | 89 | const sortedPosts = React.useMemo(() => { |
|
| 80 | - | return [...allPosts].sort((a, b) => { |
|
| 90 | + | // Filter posts based on selected feed |
|
| 91 | + | let postsToSort = allPosts; |
|
| 92 | + | if (selectedFeedId === "unread") { |
|
| 93 | + | // Show only unread posts from all feeds |
|
| 94 | + | postsToSort = allPosts.filter((post) => !isPostRead(post.id)); |
|
| 95 | + | } else if (selectedFeedId) { |
|
| 96 | + | // Show posts from specific feed |
|
| 97 | + | postsToSort = feedPostsQuery; |
|
| 98 | + | } |
|
| 99 | + | // Sort by published date (most recent first) |
|
| 100 | + | return [...postsToSort].sort((a, b) => { |
|
| 81 | 101 | if (!a.publishedDate) return 1; |
|
| 82 | 102 | if (!b.publishedDate) return -1; |
|
| 83 | 103 | return b.publishedDate.localeCompare(a.publishedDate); |
|
| 84 | 104 | }); |
|
| 85 | - | }, [allPosts]); |
|
| 105 | + | }, [allPosts, selectedFeedId, feedPostsQuery, isPostRead]); |
|
| 86 | 106 | ||
| 87 | 107 | // Get current post index and navigation info |
|
| 88 | 108 | const currentPostIndex = React.useMemo(() => { |
|
| 146 | 166 | mainContentRef.current.scrollTo({ top: 0, behavior: "smooth" }); |
|
| 147 | 167 | } |
|
| 148 | 168 | }, [selectedPostId]); |
|
| 169 | + | ||
| 170 | + | // Mark post as read when selected |
|
| 171 | + | React.useEffect(() => { |
|
| 172 | + | if (!selectedPostId || !selectedPost) return; |
|
| 173 | + | ||
| 174 | + | const existingStatus = allReadStatusesWithUnread.find( |
|
| 175 | + | (status) => status.postId === selectedPostId, |
|
| 176 | + | ); |
|
| 177 | + | ||
| 178 | + | if (existingStatus && existingStatus.isRead === 0) { |
|
| 179 | + | // Update existing status to read |
|
| 180 | + | evolu.update("readStatus", { |
|
| 181 | + | id: existingStatus.id as any, |
|
| 182 | + | isRead: 1, |
|
| 183 | + | }); |
|
| 184 | + | } else if (!existingStatus && selectedPost.feedId) { |
|
| 185 | + | // Create new read status |
|
| 186 | + | evolu.insert("readStatus", { |
|
| 187 | + | postId: selectedPostId, |
|
| 188 | + | feedId: selectedPost.feedId, |
|
| 189 | + | isRead: 1, |
|
| 190 | + | }); |
|
| 191 | + | } |
|
| 192 | + | }, [selectedPostId, selectedPost, allReadStatusesWithUnread, evolu]); |
|
| 193 | + | ||
| 194 | + | // Keyboard navigation for posts |
|
| 195 | + | React.useEffect(() => { |
|
| 196 | + | const handleKeyDown = (e: KeyboardEvent) => { |
|
| 197 | + | // Only handle arrow keys if not typing in an input/textarea |
|
| 198 | + | if ( |
|
| 199 | + | e.target instanceof HTMLInputElement || |
|
| 200 | + | e.target instanceof HTMLTextAreaElement |
|
| 201 | + | ) { |
|
| 202 | + | return; |
|
| 203 | + | } |
|
| 204 | + | ||
| 205 | + | if (e.key === "ArrowUp") { |
|
| 206 | + | e.preventDefault(); |
|
| 207 | + | goToPreviousPost(); |
|
| 208 | + | } else if (e.key === "ArrowDown") { |
|
| 209 | + | e.preventDefault(); |
|
| 210 | + | goToNextPost(); |
|
| 211 | + | } |
|
| 212 | + | }; |
|
| 213 | + | ||
| 214 | + | window.addEventListener("keydown", handleKeyDown); |
|
| 215 | + | return () => window.removeEventListener("keydown", handleKeyDown); |
|
| 216 | + | }, [goToPreviousPost, goToNextPost]); |
|
| 149 | 217 | ||
| 150 | 218 | // Get base URL from the post link to fix relative image paths |
|
| 151 | 219 | const getBaseUrl = React.useCallback((link: string | null) => { |
|