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

(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 + }