diff --git a/web/src/views/live/LiveDashboardView.tsx b/web/src/views/live/LiveDashboardView.tsx index 9cf8d7198..0d101ba96 100644 --- a/web/src/views/live/LiveDashboardView.tsx +++ b/web/src/views/live/LiveDashboardView.tsx @@ -7,7 +7,12 @@ import BirdseyeLivePlayer from "@/components/player/BirdseyeLivePlayer"; import LivePlayer from "@/components/player/LivePlayer"; import { Button } from "@/components/ui/button"; import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"; -import { TooltipProvider } from "@/components/ui/tooltip"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; import { usePersistence } from "@/hooks/use-persistence"; import { CameraConfig, FrigateConfig } from "@/types/frigateConfig"; import { ReviewSegment } from "@/types/review"; @@ -24,6 +29,8 @@ import { IoClose } from "react-icons/io5"; import { LuLayoutDashboard } from "react-icons/lu"; import { cn } from "@/lib/utils"; import { LivePlayerError, LivePlayerMode } from "@/types/live"; +import { FaCompress, FaExpand } from "react-icons/fa"; +import { useResizeObserver } from "@/hooks/resize-observer"; type LiveDashboardViewProps = { cameras: CameraConfig[]; @@ -122,6 +129,16 @@ export default function LiveDashboardView({ setPreferredLiveModes(newPreferredLiveModes); }, [cameras, config]); + const [{ height: containerHeight }] = useResizeObserver(containerRef); + + const hasScrollbar = useMemo(() => { + if (containerHeight && containerRef.current) { + return ( + containerRef.current.offsetHeight < containerRef.current.scrollHeight + ); + } + }, [containerRef, containerHeight]); + const [windowVisible, setWindowVisible] = useState(true); const visibilityListener = useCallback(() => { setWindowVisible(document.visibilityState == "visible"); @@ -277,64 +294,95 @@ export default function LiveDashboardView({ )} {!cameraGroup || cameraGroup == "default" || isMobileOnly ? ( -
- {includeBirdseye && birdseyeConfig?.enabled && ( + <> +
+ {includeBirdseye && birdseyeConfig?.enabled && ( +
{ + const aspectRatio = + birdseyeConfig.width / birdseyeConfig.height; + if (aspectRatio > 2) { + return `${mobileLayout == "grid" && "col-span-2"} aspect-wide`; + } else if (aspectRatio < 1) { + return `${mobileLayout == "grid" && "row-span-2 h-full"} aspect-tall`; + } else { + return "aspect-video"; + } + })()} + ref={birdseyeContainerRef} + > + onSelectCamera("birdseye")} + containerRef={birdseyeContainerRef} + /> +
+ )} + {cameras.map((camera) => { + let grow; + const aspectRatio = camera.detect.width / camera.detect.height; + if (aspectRatio > 2) { + grow = `${mobileLayout == "grid" && "col-span-2"} aspect-wide`; + } else if (aspectRatio < 1) { + grow = `${mobileLayout == "grid" && "row-span-2 h-full"} aspect-tall`; + } else { + grow = "aspect-video"; + } + return ( + onSelectCamera(camera.name)} + onError={(e) => handleError(camera.name, e)} + /> + ); + })} +
+ {isDesktop && (
{ - const aspectRatio = - birdseyeConfig.width / birdseyeConfig.height; - if (aspectRatio > 2) { - return `${mobileLayout == "grid" && "col-span-2"} aspect-wide`; - } else if (aspectRatio < 1) { - return `${mobileLayout == "grid" && "row-span-2 h-full"} aspect-tall`; - } else { - return "aspect-video"; - } - })()} - ref={birdseyeContainerRef} + className={cn( + "fixed", + isDesktop && "bottom-12 lg:bottom-9", + isMobile && "bottom-12 lg:bottom-16", + hasScrollbar && isDesktop ? "right-6" : "right-3", + "z-50 flex flex-row gap-2", + )} > - onSelectCamera("birdseye")} - containerRef={birdseyeContainerRef} - /> + + +
+ {fullscreen ? ( + + ) : ( + + )} +
+
+ + {fullscreen ? "Exit Fullscreen" : "Fullscreen"} + +
)} - {cameras.map((camera) => { - let grow; - const aspectRatio = camera.detect.width / camera.detect.height; - if (aspectRatio > 2) { - grow = `${mobileLayout == "grid" && "col-span-2"} aspect-wide`; - } else if (aspectRatio < 1) { - grow = `${mobileLayout == "grid" && "row-span-2 h-full"} aspect-tall`; - } else { - grow = "aspect-video"; - } - return ( - onSelectCamera(camera.name)} - onError={(e) => handleError(camera.name, e)} - /> - ); - })} -
+ ) : (