mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-18 00:54:27 +03:00
live context menu component
This commit is contained in:
parent
84fcc56fef
commit
de8d06b119
142
web/src/components/menu/LiveContextMenu.tsx
Normal file
142
web/src/components/menu/LiveContextMenu.tsx
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
import { ReactNode, useMemo } from "react";
|
||||||
|
import {
|
||||||
|
ContextMenu,
|
||||||
|
ContextMenuContent,
|
||||||
|
ContextMenuItem,
|
||||||
|
ContextMenuSeparator,
|
||||||
|
ContextMenuTrigger,
|
||||||
|
} from "@/components/ui/context-menu";
|
||||||
|
import {
|
||||||
|
MdVolumeDown,
|
||||||
|
MdVolumeMute,
|
||||||
|
MdVolumeOff,
|
||||||
|
MdVolumeUp,
|
||||||
|
} from "react-icons/md";
|
||||||
|
import { VolumeSlider } from "@/components/ui/slider";
|
||||||
|
|
||||||
|
type LiveContextMenuProps = {
|
||||||
|
camera: string;
|
||||||
|
preferredLiveMode: string;
|
||||||
|
isRestreamed: boolean;
|
||||||
|
supportsAudio: boolean;
|
||||||
|
audioState: boolean;
|
||||||
|
toggleAudio: () => void;
|
||||||
|
volumeState?: number;
|
||||||
|
setVolumeState: (volumeState: number) => void;
|
||||||
|
muteAll: () => void;
|
||||||
|
unmuteAll: () => void;
|
||||||
|
resetPreferredLiveMode: () => void;
|
||||||
|
children?: ReactNode;
|
||||||
|
};
|
||||||
|
export default function LiveContextMenu({
|
||||||
|
camera,
|
||||||
|
preferredLiveMode,
|
||||||
|
isRestreamed,
|
||||||
|
supportsAudio,
|
||||||
|
audioState,
|
||||||
|
toggleAudio,
|
||||||
|
volumeState,
|
||||||
|
setVolumeState,
|
||||||
|
muteAll,
|
||||||
|
unmuteAll,
|
||||||
|
resetPreferredLiveMode,
|
||||||
|
children,
|
||||||
|
}: LiveContextMenuProps) {
|
||||||
|
const VolumeIcon = useMemo(() => {
|
||||||
|
if (!volumeState || volumeState == 0.0 || !audioState) {
|
||||||
|
return MdVolumeOff;
|
||||||
|
} else if (volumeState <= 0.33) {
|
||||||
|
return MdVolumeMute;
|
||||||
|
} else if (volumeState <= 0.67) {
|
||||||
|
return MdVolumeDown;
|
||||||
|
} else {
|
||||||
|
return MdVolumeUp;
|
||||||
|
}
|
||||||
|
// only update when specific fields change
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [volumeState, audioState]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ContextMenu key={camera}>
|
||||||
|
<ContextMenuTrigger>{children}</ContextMenuTrigger>
|
||||||
|
<ContextMenuContent>
|
||||||
|
<div className="text-md py-1 pl-2 capitalize text-primary-variant">
|
||||||
|
{camera.replaceAll("_", " ")}
|
||||||
|
</div>
|
||||||
|
{preferredLiveMode != "jsmpeg" && isRestreamed && supportsAudio && (
|
||||||
|
<>
|
||||||
|
<ContextMenuSeparator className="mb-1" />
|
||||||
|
<div className="p-2 text-sm">
|
||||||
|
<div className="flex w-full flex-col gap-1">
|
||||||
|
<p>Audio</p>
|
||||||
|
<div className="flex flex-row items-center gap-1">
|
||||||
|
<VolumeIcon
|
||||||
|
className="size-5"
|
||||||
|
onClick={(e: React.MouseEvent) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
toggleAudio();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<VolumeSlider
|
||||||
|
disabled={!audioState}
|
||||||
|
className="my-3 ml-0.5 rounded-lg bg-background/60"
|
||||||
|
value={[volumeState ?? 0]}
|
||||||
|
min={0}
|
||||||
|
max={1}
|
||||||
|
step={0.02}
|
||||||
|
onValueChange={(value) => {
|
||||||
|
setVolumeState(value[0]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<ContextMenuSeparator />
|
||||||
|
<ContextMenuItem>
|
||||||
|
<div
|
||||||
|
className="flex w-full cursor-pointer items-center justify-start gap-2"
|
||||||
|
onClick={muteAll}
|
||||||
|
>
|
||||||
|
<div className="text-primary">Mute All Cameras</div>
|
||||||
|
</div>
|
||||||
|
</ContextMenuItem>
|
||||||
|
<ContextMenuItem>
|
||||||
|
<div
|
||||||
|
className="flex w-full cursor-pointer items-center justify-start gap-2"
|
||||||
|
onClick={unmuteAll}
|
||||||
|
>
|
||||||
|
<div className="text-primary">Unmute All Cameras</div>
|
||||||
|
</div>
|
||||||
|
</ContextMenuItem>
|
||||||
|
{isRestreamed && (
|
||||||
|
<>
|
||||||
|
<ContextMenuSeparator />
|
||||||
|
<ContextMenuItem>
|
||||||
|
<div
|
||||||
|
className="flex w-full cursor-pointer items-center justify-start gap-2"
|
||||||
|
onClick={() => {}}
|
||||||
|
>
|
||||||
|
<div className="text-primary">Streaming Settings</div>
|
||||||
|
</div>
|
||||||
|
</ContextMenuItem>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{preferredLiveMode == "jsmpeg" && isRestreamed && (
|
||||||
|
<>
|
||||||
|
<ContextMenuSeparator />
|
||||||
|
<ContextMenuItem>
|
||||||
|
<div
|
||||||
|
className="flex w-full cursor-pointer items-center justify-start gap-2"
|
||||||
|
onClick={resetPreferredLiveMode}
|
||||||
|
>
|
||||||
|
<div className="text-primary">Reset</div>
|
||||||
|
</div>
|
||||||
|
</ContextMenuItem>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</ContextMenuContent>
|
||||||
|
</ContextMenu>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user