an independent Bluesky client using Constellation, PDS Queries, and other services reddwarf.app
frontend spa bluesky reddwarf microcosm client app
99
fork

Configure Feed

Select the types of activity you want to include in your feed.

notif tabs scroll restoration

rimar1337 d14e2ae8 61ce2144

+68 -10
+59 -10
src/routes/notifications.tsx
··· 4 4 import { createFileRoute, Link, useNavigate } from "@tanstack/react-router"; 5 5 import { useAtom } from "jotai"; 6 6 import * as React from "react"; 7 + import { useEffect, useLayoutEffect } from "react"; 7 8 8 9 import defaultpfp from "~/../public/favicon.png"; 9 10 import { Header } from "~/components/Header"; ··· 14 15 UniversalPostRendererATURILoader, 15 16 } from "~/components/UniversalPostRenderer"; 16 17 import { useAuth } from "~/providers/UnifiedAuthProvider"; 17 - import { constellationURLAtom, imgCDNAtom, isAtTopAtom } from "~/utils/atoms"; 18 + import { 19 + constellationURLAtom, 20 + imgCDNAtom, 21 + isAtTopAtom, 22 + notificationsScrollAtom, 23 + } from "~/utils/atoms"; 18 24 import { 19 25 useInfiniteQueryAuthorFeed, 20 26 useQueryConstellation, ··· 49 55 }); 50 56 51 57 export default function NotificationsTabs() { 52 - const [activeTab, setActiveTab] = React.useState("mentions"); 58 + const [notifState, setNotifState] = useAtom(notificationsScrollAtom); 59 + const activeTab = notifState.activeTab; 53 60 const [isAtTop] = useAtom(isAtTopAtom); 54 - 55 - const scrollPositions = React.useRef<Record<string, number>>({}); 56 61 57 62 const handleValueChange = (newTab: string) => { 58 - scrollPositions.current[activeTab] = window.scrollY; 59 - setActiveTab(newTab); 63 + console.log(newTab); 64 + setNotifState((prev) => { 65 + const wow = { 66 + ...prev, 67 + scrollPositions: { 68 + ...prev.scrollPositions, 69 + [prev.activeTab]: window.scrollY, 70 + }, 71 + activeTab: newTab, 72 + }; 73 + //console.log(wow); 74 + return wow; 75 + }); 60 76 }; 61 77 62 - React.useEffect(() => { 63 - const savedY = scrollPositions.current[activeTab] ?? 0; 64 - window.scrollTo(0, savedY); 65 - }, [activeTab]); 78 + useLayoutEffect(() => { 79 + return () => { 80 + setNotifState((prev) => { 81 + const wow = { 82 + ...prev, 83 + scrollPositions: { 84 + ...prev.scrollPositions, 85 + [activeTab]: window.scrollY, 86 + }, 87 + }; 88 + //console.log(wow); 89 + return wow; 90 + }); 91 + } 92 + // eslint-disable-next-line react-hooks/exhaustive-deps 93 + }, []); 66 94 67 95 return ( 68 96 <TabsPrimitive.Root ··· 138 166 ); 139 167 }, [infiniteMentionsData]); 140 168 169 + const [notifState] = useAtom(notificationsScrollAtom); 170 + const activeTab = notifState.activeTab; 171 + useEffect(() => { 172 + const savedY = notifState.scrollPositions[activeTab] ?? 0; 173 + window.scrollTo(0, savedY); 174 + }, [activeTab, notifState.scrollPositions]); 175 + 141 176 if (isLoading) return <LoadingState text="Loading mentions..." />; 142 177 if (isError) return <ErrorState error={error} />; 143 178 ··· 200 235 ); 201 236 }, [infiniteFollowsData]); 202 237 238 + const [notifState] = useAtom(notificationsScrollAtom); 239 + const activeTab = notifState.activeTab; 240 + useEffect(() => { 241 + const savedY = notifState.scrollPositions[activeTab] ?? 0; 242 + window.scrollTo(0, savedY); 243 + }, [activeTab, notifState.scrollPositions]); 244 + 203 245 if (isLoading) return <LoadingState text="Loading mentions..." />; 204 246 if (isError) return <ErrorState error={error} />; 205 247 ··· 252 294 () => postsData?.pages.flatMap((page) => page.records) ?? [], 253 295 [postsData] 254 296 ); 297 + 298 + const [notifState] = useAtom(notificationsScrollAtom); 299 + const activeTab = notifState.activeTab; 300 + useEffect(() => { 301 + const savedY = notifState.scrollPositions[activeTab] ?? 0; 302 + window.scrollTo(0, savedY); 303 + }, [activeTab, notifState.scrollPositions]); 255 304 256 305 return ( 257 306 <>
+9
src/utils/atoms.ts
··· 21 21 {} 22 22 ); 23 23 24 + type NotificationsScrollState = { 25 + activeTab: string; 26 + scrollPositions: Record<string, number>; 27 + }; 28 + export const notificationsScrollAtom = atom<NotificationsScrollState>({ 29 + activeTab: "mentions", 30 + scrollPositions: {}, 31 + }); 32 + 24 33 export const likedPostsAtom = atomWithStorage<Record<string, string>>( 25 34 "likedPosts", 26 35 {}