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)}
- />
- );
- })}
-
+ >
) : (