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.

(unused) experimental sticky

+52 -21
+52 -21
src/components/ReusableTabRoute.tsx
··· 1 1 import * as TabsPrimitive from "@radix-ui/react-tabs"; 2 2 import { useAtom } from "jotai"; 3 - import { useEffect, useLayoutEffect } from "react"; 3 + import { useEffect, useLayoutEffect, useRef, useState } from "react"; 4 4 5 5 import { isAtTopAtom, reusableTabRouteScrollAtom } from "~/utils/atoms"; 6 6 ··· 70 70 // eslint-disable-next-line react-hooks/exhaustive-deps 71 71 }, []); 72 72 73 + //const { sentinelRef, isStuck } = useSticky(52); 74 + //bg-gray-100 dark:bg-gray-900 75 + 73 76 return ( 74 - <TabsPrimitive.Root 75 - value={activeTab} 76 - onValueChange={handleValueChange} 77 - className={`w-full`} 78 - > 79 - <TabsPrimitive.List 80 - className={`flex sticky top-[52px] bg-[var(--header-bg-light)] dark:bg-[var(--header-bg-dark)] z-[9] border-0 sm:border-b ${!isAtTop && "shadow-sm"} sm:shadow-none sm:dark:bg-gray-950 sm:bg-white border-gray-200 dark:border-gray-700`} 77 + <> 78 + <TabsPrimitive.Root 79 + value={activeTab} 80 + onValueChange={handleValueChange} 81 + className={`w-full`} 81 82 > 82 - {Object.entries(tabs).map(([key]) => ( 83 - <TabsPrimitive.Trigger key={key} value={key} className="m3tab"> 84 - {key} 85 - </TabsPrimitive.Trigger> 83 + {/* <div ref={sentinelRef} className="h-[0.000000001px]" /> */} 84 + <TabsPrimitive.List 85 + className={`flex sticky top-[52px] bg-[var(--header-bg-light)] dark:bg-[var(--header-bg-dark)] sm:dark:bg-gray-950 sm:bg-white z-[9] border-0 sm:border-b ${!isAtTop && "shadow-sm"} sm:shadow-none border-gray-200 dark:border-gray-700`} 86 + > 87 + {Object.entries(tabs).map(([key]) => ( 88 + <TabsPrimitive.Trigger key={key} value={key} className="m3tab"> 89 + {key} 90 + </TabsPrimitive.Trigger> 91 + ))} 92 + </TabsPrimitive.List> 93 + 94 + {Object.entries(tabs).map(([key, node]) => ( 95 + <TabsPrimitive.Content key={key} value={key} className="flex-1 min-h-[80dvh]"> 96 + {activeTab === key && node} 97 + </TabsPrimitive.Content> 86 98 ))} 87 - </TabsPrimitive.List> 88 - 89 - {Object.entries(tabs).map(([key, node]) => ( 90 - <TabsPrimitive.Content key={key} value={key} className="flex-1 min-h-[80dvh]"> 91 - {activeTab === key && node} 92 - </TabsPrimitive.Content> 93 - ))} 94 - </TabsPrimitive.Root> 99 + </TabsPrimitive.Root> 100 + </> 101 + 95 102 ); 96 103 } 97 104 ··· 121 128 window.scrollTo(0, savedY); 122 129 }, [activeTab, notifState.scrollPositions]); 123 130 124 - */ 131 + */ 132 + 133 + 134 + 135 + export function useSticky(top: number = 0) { 136 + const sentinelRef = useRef<HTMLDivElement | null>(null); 137 + const [isStuck, setIsStuck] = useState(false); 138 + 139 + useEffect(() => { 140 + if (!sentinelRef.current) return; 141 + 142 + const observer = new IntersectionObserver( 143 + ([entry]) => setIsStuck(!entry.isIntersecting), 144 + { 145 + rootMargin: `-${top}px 0px 0px 0px`, 146 + threshold: 0, 147 + } 148 + ); 149 + 150 + observer.observe(sentinelRef.current); 151 + return () => observer.disconnect(); 152 + }, [top]); 153 + 154 + return { sentinelRef, isStuck }; 155 + }