Various UI tweaks (#12061)

This commit is contained in:
Josh Hawkins 2024-06-19 06:09:49 -06:00 committed by GitHub
parent 767033e4d8
commit 7b57a66d45
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 29 additions and 4 deletions

View File

@ -1,8 +1,9 @@
import { baseUrl } from "@/api/baseUrl"; import { baseUrl } from "@/api/baseUrl";
import { useResizeObserver } from "@/hooks/resize-observer"; import { useResizeObserver } from "@/hooks/resize-observer";
import { cn } from "@/lib/utils";
// @ts-expect-error we know this doesn't have types // @ts-expect-error we know this doesn't have types
import JSMpeg from "@cycjimmy/jsmpeg-player"; import JSMpeg from "@cycjimmy/jsmpeg-player";
import React, { useEffect, useMemo, useRef, useId } from "react"; import React, { useEffect, useMemo, useRef, useId, useState } from "react";
type JSMpegPlayerProps = { type JSMpegPlayerProps = {
className?: string; className?: string;
@ -26,6 +27,7 @@ export default function JSMpegPlayer({
const videoRef = useRef(null); const videoRef = useRef(null);
const internalContainerRef = useRef<HTMLDivElement | null>(null); const internalContainerRef = useRef<HTMLDivElement | null>(null);
const onPlayingRef = useRef(onPlaying); const onPlayingRef = useRef(onPlaying);
const [showCanvas, setShowCanvas] = useState(false);
const selectedContainerRef = useMemo( const selectedContainerRef = useMemo(
() => containerRef ?? internalContainerRef, () => containerRef ?? internalContainerRef,
@ -101,6 +103,7 @@ export default function JSMpegPlayer({
audio: false, audio: false,
videoBufferSize: 1024 * 1024 * 4, videoBufferSize: 1024 * 1024 * 4,
onPlay: () => { onPlay: () => {
setShowCanvas(true);
onPlayingRef.current?.(); onPlayingRef.current?.();
}, },
}, },
@ -110,7 +113,7 @@ export default function JSMpegPlayer({
return ( return (
<div className={className}> <div className={className}>
<div className="size-full" ref={internalContainerRef}> <div className="size-full" ref={internalContainerRef}>
<div ref={playerRef} className="jsmpeg"> <div ref={playerRef} className={cn("jsmpeg", !showCanvas && "hidden")}>
<canvas <canvas
id={uniqueId} id={uniqueId}
style={{ style={{

View File

@ -18,6 +18,7 @@ import { getIconForLabel } from "@/utils/iconUtil";
import Chip from "../indicators/Chip"; import Chip from "../indicators/Chip";
import { capitalizeFirstLetter } from "@/utils/stringUtil"; import { capitalizeFirstLetter } from "@/utils/stringUtil";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { TbExclamationCircle } from "react-icons/tb";
type LivePlayerProps = { type LivePlayerProps = {
cameraRef?: (ref: HTMLDivElement | null) => void; cameraRef?: (ref: HTMLDivElement | null) => void;
@ -275,6 +276,16 @@ export default function LivePlayer({
/> />
</div> </div>
{offline && !showStillWithoutActivity && (
<div className="flex size-full flex-col items-center">
<p className="mb-5">
{capitalizeFirstLetter(cameraConfig.name)} is offline
</p>
<TbExclamationCircle className="mb-3 size-10" />
<p>No frames have been received, check error logs</p>
</div>
)}
<div className="absolute right-2 top-2"> <div className="absolute right-2 top-2">
{autoLive && {autoLive &&
!offline && !offline &&
@ -282,7 +293,7 @@ export default function LivePlayer({
((showStillWithoutActivity && !liveReady) || liveReady) && ( ((showStillWithoutActivity && !liveReady) || liveReady) && (
<MdCircle className="mr-2 size-2 animate-pulse text-danger shadow-danger drop-shadow-md" /> <MdCircle className="mr-2 size-2 animate-pulse text-danger shadow-danger drop-shadow-md" />
)} )}
{offline && ( {offline && showStillWithoutActivity && (
<Chip <Chip
className={`z-0 flex items-start justify-between space-x-1 bg-gray-500 bg-gradient-to-br from-gray-400 to-gray-500 text-xs capitalize`} className={`z-0 flex items-start justify-between space-x-1 bg-gray-500 bg-gradient-to-br from-gray-400 to-gray-500 text-xs capitalize`}
> >

View File

@ -2,6 +2,7 @@ import { useFullscreen } from "@/hooks/use-fullscreen";
import { import {
useHashState, useHashState,
usePersistedOverlayState, usePersistedOverlayState,
useSearchEffect,
} from "@/hooks/use-overlay-state"; } from "@/hooks/use-overlay-state";
import { FrigateConfig } from "@/types/frigateConfig"; import { FrigateConfig } from "@/types/frigateConfig";
import LiveBirdseyeView from "@/views/live/LiveBirdseyeView"; import LiveBirdseyeView from "@/views/live/LiveBirdseyeView";
@ -16,11 +17,21 @@ function Live() {
// selection // selection
const [selectedCameraName, setSelectedCameraName] = useHashState(); const [selectedCameraName, setSelectedCameraName] = useHashState();
const [cameraGroup] = usePersistedOverlayState( const [cameraGroup, setCameraGroup] = usePersistedOverlayState(
"cameraGroup", "cameraGroup",
"default" as string, "default" as string,
); );
useSearchEffect("group", (cameraGroup) => {
if (config && cameraGroup) {
const group = config.camera_groups[cameraGroup];
if (group) {
setCameraGroup(cameraGroup);
}
}
});
// fullscreen // fullscreen
const mainRef = useRef<HTMLDivElement | null>(null); const mainRef = useRef<HTMLDivElement | null>(null);