mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	More intelligent timeline scrolling (#10209)
* more intelligent timeline scrolling * keep as div
This commit is contained in:
		
							parent
							
								
									8645545ef4
								
							
						
					
					
						commit
						312dc95156
					
				
							
								
								
									
										14
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -52,6 +52,7 @@ | ||||
|         "react-transition-group": "^4.4.5", | ||||
|         "react-use-websocket": "^4.7.0", | ||||
|         "recoil": "^0.7.7", | ||||
|         "scroll-into-view-if-needed": "^3.1.0", | ||||
|         "sonner": "^1.4.0", | ||||
|         "sort-by": "^1.2.0", | ||||
|         "strftime": "^0.10.2", | ||||
| @ -3761,6 +3762,11 @@ | ||||
|         "node": ">= 6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/compute-scroll-into-view": { | ||||
|       "version": "3.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz", | ||||
|       "integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==" | ||||
|     }, | ||||
|     "node_modules/concat-map": { | ||||
|       "version": "0.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", | ||||
| @ -7213,6 +7219,14 @@ | ||||
|         "loose-envify": "^1.1.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/scroll-into-view-if-needed": { | ||||
|       "version": "3.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", | ||||
|       "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==", | ||||
|       "dependencies": { | ||||
|         "compute-scroll-into-view": "^3.0.2" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/semver": { | ||||
|       "version": "7.5.4", | ||||
|       "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", | ||||
|  | ||||
| @ -57,6 +57,7 @@ | ||||
|     "react-transition-group": "^4.4.5", | ||||
|     "react-use-websocket": "^4.7.0", | ||||
|     "recoil": "^0.7.7", | ||||
|     "scroll-into-view-if-needed": "^3.1.0", | ||||
|     "sonner": "^1.4.0", | ||||
|     "sort-by": "^1.2.0", | ||||
|     "strftime": "^0.10.2", | ||||
|  | ||||
| @ -71,7 +71,7 @@ export default function ReviewFilterGroup({ | ||||
|   ); | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="mr-2"> | ||||
|     <div> | ||||
|       <CamerasFilterButton | ||||
|         allCameras={filterValues.cameras} | ||||
|         selectedCameras={filter?.cameras} | ||||
| @ -246,7 +246,7 @@ function GeneralFilterButton({ | ||||
|   return ( | ||||
|     <Popover> | ||||
|       <PopoverTrigger asChild> | ||||
|         <Button size="sm" className="mx-1" variant="secondary"> | ||||
|         <Button size="sm" className="ml-1" variant="secondary"> | ||||
|           <FaFilter className="md:mr-[10px] text-muted-foreground" /> | ||||
|           <div className="hidden md:block">Filter</div> | ||||
|         </Button> | ||||
|  | ||||
| @ -16,6 +16,7 @@ import { | ||||
|   HoverCardTrigger, | ||||
| } from "../ui/hover-card"; | ||||
| import { HoverCardPortal } from "@radix-ui/react-hover-card"; | ||||
| import scrollIntoView from "scroll-into-view-if-needed"; | ||||
| 
 | ||||
| type EventSegmentProps = { | ||||
|   events: ReviewSegment[]; | ||||
| @ -225,20 +226,14 @@ export function EventSegment({ | ||||
| 
 | ||||
|   const firstMinimapSegmentRef = useRef<HTMLDivElement>(null); | ||||
| 
 | ||||
|   let debounceTimer: ReturnType<typeof setTimeout>; | ||||
| 
 | ||||
|   function debounceScrollIntoView(element: HTMLElement) { | ||||
|     clearTimeout(debounceTimer); | ||||
|     debounceTimer = setTimeout(() => { | ||||
|       element.scrollIntoView({ behavior: "smooth", block: "center" }); | ||||
|     }, 100); | ||||
|   } | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     // Check if the first segment is out of view
 | ||||
|     const firstSegment = firstMinimapSegmentRef.current; | ||||
|     if (firstSegment && showMinimap && isFirstSegmentInMinimap) { | ||||
|       debounceScrollIntoView(firstSegment); | ||||
|       scrollIntoView(firstSegment, { | ||||
|         scrollMode: "if-needed", | ||||
|         behavior: "smooth", | ||||
|       }); | ||||
|     } | ||||
|     // we know that these deps are correct
 | ||||
|     // eslint-disable-next-line react-hooks/exhaustive-deps
 | ||||
| @ -276,7 +271,10 @@ export function EventSegment({ | ||||
|         `[data-segment-start="${startTimestamp - segmentDuration}"]`, | ||||
|       ); | ||||
|       if (element instanceof HTMLElement) { | ||||
|         debounceScrollIntoView(element); | ||||
|         scrollIntoView(element, { | ||||
|           scrollMode: "if-needed", | ||||
|           behavior: "smooth", | ||||
|         }); | ||||
|         element.classList.add( | ||||
|           `outline-severity_${severityType}`, | ||||
|           `shadow-severity_${severityType}`, | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| import { useCallback, useEffect } from "react"; | ||||
| import scrollIntoView from "scroll-into-view-if-needed"; | ||||
| 
 | ||||
| type DragHandlerProps = { | ||||
|   contentRef: React.RefObject<HTMLElement>; | ||||
| @ -75,6 +76,10 @@ function useDraggableHandler({ | ||||
|               minute: "2-digit", | ||||
|               ...(segmentDuration < 60 && { second: "2-digit" }), | ||||
|             }); | ||||
|             scrollIntoView(thumb, { | ||||
|               scrollMode: "if-needed", | ||||
|               behavior: "smooth", | ||||
|             }); | ||||
|           } | ||||
|         }); | ||||
|         if (setHandlebarTime) { | ||||
| @ -167,11 +172,6 @@ function useDraggableHandler({ | ||||
|         scrolled; | ||||
| 
 | ||||
|       updateHandlebarPosition(newHandlePosition - segmentHeight, handlebarTime); | ||||
| 
 | ||||
|       scrollTimeRef.current.scrollIntoView({ | ||||
|         behavior: "smooth", | ||||
|         block: "center", | ||||
|       }); | ||||
|     } | ||||
|     // we know that these deps are correct
 | ||||
|     // eslint-disable-next-line react-hooks/exhaustive-deps
 | ||||
|  | ||||
| @ -247,12 +247,12 @@ export default function EventView({ | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="flex flex-col size-full"> | ||||
|       <div className="h-10 relative flex justify-between items-center mb-2"> | ||||
|       <div className="h-10 relative flex justify-between items-center m-2"> | ||||
|         {isMobile && ( | ||||
|           <Logo className="absolute inset-y-0 inset-x-1/2 -translate-x-1/2 h-8" /> | ||||
|         )} | ||||
|         <ToggleGroup | ||||
|           className="*:px-3 *:py4 *:rounded-2xl" | ||||
|           className="*:px-3 *:py-4 *:rounded-2xl" | ||||
|           type="single" | ||||
|           defaultValue="alert" | ||||
|           size="sm" | ||||
| @ -315,7 +315,7 @@ export default function EventView({ | ||||
|           {!isValidating && currentItems == null && ( | ||||
|             <div className="size-full flex flex-col justify-center items-center"> | ||||
|               <LuFolderCheck className="size-16" /> | ||||
|               There are no {severity} items to review | ||||
|               There are no {severity.replace(/_/g, " ")} items to review | ||||
|             </div> | ||||
|           )} | ||||
| 
 | ||||
|  | ||||
| @ -120,7 +120,7 @@ export default function LiveDashboardView({ | ||||
|       )} | ||||
| 
 | ||||
|       <div | ||||
|         className={`mt-4 grid ${layout == "grid" ? "grid-cols-2 xl:grid-cols-3 3xl:grid-cols-4" : ""} gap-2 md:gap-4  *:rounded-2xl *:bg-black`} | ||||
|         className={`my-4 grid ${layout == "grid" ? "grid-cols-2 xl:grid-cols-3 3xl:grid-cols-4" : ""} gap-2 md:gap-4  *:rounded-2xl *:bg-black`} | ||||
|       > | ||||
|         {cameras.map((camera) => { | ||||
|           let grow; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user