pstream is dead; long live pstream taciturnaxolotl.github.io/pstream-ng/
1
fork

Configure Feed

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

thumbnail styling

Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com>

mrjvs fcec845f 068b7071

+55 -19
+55 -19
src/components/player/atoms/ProgressBar.tsx
··· 13 13 import { usePlayerStore } from "@/stores/player/store"; 14 14 import { durationExceedsHour, formatSeconds } from "@/utils/formatSeconds"; 15 15 16 - function ThumbnailDisplay(props: { at: number }) { 16 + function ThumbnailDisplay(props: { at: number; show: boolean }) { 17 17 const thumbnailImages = usePlayerStore((s) => s.thumbnails.images); 18 18 const currentThumbnail = useMemo(() => { 19 19 return nearestImageAt(thumbnailImages, props.at)?.image; 20 20 }, [thumbnailImages, props.at]); 21 + const [offsets, setOffsets] = useState({ 22 + offscreenLeft: 0, 23 + offscreenRight: 0, 24 + }); 25 + const ref = useRef<HTMLImageElement>(null); 21 26 22 - if (!currentThumbnail) return null; 27 + useEffect(() => { 28 + if (!ref.current) return; 29 + const rect = ref.current.getBoundingClientRect(); 30 + const padding = 32; 31 + const left = Math.max(0, (rect.left - padding) * -1); 32 + const right = Math.max(0, rect.right + padding - window.innerWidth); 33 + 34 + setOffsets({ 35 + offscreenLeft: left, 36 + offscreenRight: right, 37 + }); 38 + }, [props.at]); 39 + 40 + if (!props.show || !currentThumbnail) return null; 23 41 return ( 24 42 <div className="flex flex-col items-center -translate-x-1/2"> 25 - <img 26 - src={currentThumbnail.data} 27 - className="h-24 border rounded-xl border-gray-800" 28 - /> 29 - <p className="text-center"> 30 - {formatSeconds(props.at, durationExceedsHour(props.at))} 31 - </p> 43 + <div className="w-screen flex justify-center"> 44 + <div ref={ref}> 45 + <div 46 + style={{ 47 + transform: `translateX(${ 48 + offsets.offscreenLeft > 0 49 + ? offsets.offscreenLeft 50 + : -offsets.offscreenRight 51 + }px)`, 52 + }} 53 + > 54 + <img 55 + src={currentThumbnail.data} 56 + className="h-24 border rounded-xl border-gray-800" 57 + /> 58 + <p className="text-center mt-1"> 59 + {formatSeconds( 60 + Math.max(props.at, 0), 61 + durationExceedsHour(props.at) 62 + )} 63 + </p> 64 + </div> 65 + </div> 66 + </div> 32 67 </div> 33 68 ); 34 69 } ··· 86 121 return ( 87 122 <div className="w-full relative"> 88 123 <div className="top-0 absolute inset-x-0"> 89 - {mousePos > -1 ? ( 90 - <div 91 - className="absolute bottom-0" 92 - style={{ 93 - left: `${mousePos}%`, 94 - }} 95 - > 96 - <ThumbnailDisplay at={Math.floor((mousePos / 100) * duration)} /> 97 - </div> 98 - ) : null} 124 + <div 125 + className="absolute bottom-0" 126 + style={{ 127 + left: `${mousePos}%`, 128 + }} 129 + > 130 + <ThumbnailDisplay 131 + at={Math.floor((mousePos / 100) * duration)} 132 + show={mousePos > -1} 133 + /> 134 + </div> 99 135 </div> 100 136 101 137 <div className="w-full" ref={ref}>