mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Update camera activity indicator (#10208)
* new indicator * create indicators directory and update imports * create indicators directory and update imports * remove vite
This commit is contained in:
parent
312dc95156
commit
c74eb75554
@ -2,7 +2,7 @@ import { FrigateConfig } from "@/types/frigateConfig";
|
|||||||
import { GraphDataPoint } from "@/types/graph";
|
import { GraphDataPoint } from "@/types/graph";
|
||||||
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
|
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import ActivityIndicator from "../ui/activity-indicator";
|
import ActivityIndicator from "../indicators/activity-indicator";
|
||||||
|
|
||||||
type TimelineBarProps = {
|
type TimelineBarProps = {
|
||||||
startTime: number;
|
startTime: number;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useApiHost } from "@/api";
|
import { useApiHost } from "@/api";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import ActivityIndicator from "../ui/activity-indicator";
|
import ActivityIndicator from "../indicators/activity-indicator";
|
||||||
|
|
||||||
type CameraImageProps = {
|
type CameraImageProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useApiHost } from "@/api";
|
import { useApiHost } from "@/api";
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import ActivityIndicator from "../ui/activity-indicator";
|
import ActivityIndicator from "../indicators/activity-indicator";
|
||||||
import { useResizeObserver } from "@/hooks/resize-observer";
|
import { useResizeObserver } from "@/hooks/resize-observer";
|
||||||
|
|
||||||
type CameraImageProps = {
|
type CameraImageProps = {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { baseUrl } from "@/api/baseUrl";
|
import { baseUrl } from "@/api/baseUrl";
|
||||||
import ActivityIndicator from "../ui/activity-indicator";
|
import ActivityIndicator from "../indicators/activity-indicator";
|
||||||
import { Card } from "../ui/card";
|
import { Card } from "../ui/card";
|
||||||
import { LuPlay, LuTrash } from "react-icons/lu";
|
import { LuPlay, LuTrash } from "react-icons/lu";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
|
33
web/src/components/indicators/CameraActivityIndicator.tsx
Normal file
33
web/src/components/indicators/CameraActivityIndicator.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
function CameraActivityIndicator() {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center relative z-20">
|
||||||
|
<div className="flex">
|
||||||
|
<div className="absolute size-[5px] inset-0 bg-severity_alert-dimmed rounded-full shadow-[0px_0px_10px_0px_#00000024,0px_0px_15px_0px_#00000024] z-20 animate-move"></div>
|
||||||
|
<div className="flex-1 size-[5px] mr-[2px] bg-severity_alert rounded-full animate-scale1"></div>
|
||||||
|
<div className="flex-1 size-[5px] mr-[2px] bg-severity_alert rounded-full animate-scale2"></div>
|
||||||
|
<div className="flex-1 size-[5px] mr-[2px] bg-severity_alert rounded-full animate-scale3"></div>
|
||||||
|
<div className="flex-1 size-[5px] mr-[2px] bg-severity_alert rounded-full animate-scale4"></div>
|
||||||
|
</div>
|
||||||
|
<svg className="hidden" xmlns="http://www.w3.org/2000/svg" version="1.1">
|
||||||
|
<defs>
|
||||||
|
<filter id="goo">
|
||||||
|
<feGaussianBlur
|
||||||
|
in="SourceGraphic"
|
||||||
|
stdDeviation="10"
|
||||||
|
result="blur"
|
||||||
|
/>
|
||||||
|
<feColorMatrix
|
||||||
|
in="blur"
|
||||||
|
type="matrix"
|
||||||
|
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7"
|
||||||
|
result="goo"
|
||||||
|
/>
|
||||||
|
<feBlend in="SourceGraphic" in2="goo" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CameraActivityIndicator;
|
@ -1,6 +1,6 @@
|
|||||||
import WebRtcPlayer from "./WebRTCPlayer";
|
import WebRtcPlayer from "./WebRTCPlayer";
|
||||||
import { BirdseyeConfig } from "@/types/frigateConfig";
|
import { BirdseyeConfig } from "@/types/frigateConfig";
|
||||||
import ActivityIndicator from "../ui/activity-indicator";
|
import ActivityIndicator from "../indicators/activity-indicator";
|
||||||
import JSMpegPlayer from "./JSMpegPlayer";
|
import JSMpegPlayer from "./JSMpegPlayer";
|
||||||
import MSEPlayer from "./MsePlayer";
|
import MSEPlayer from "./MsePlayer";
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import TimelineEventOverlay from "../overlay/TimelineDataOverlay";
|
|||||||
import { useApiHost } from "@/api";
|
import { useApiHost } from "@/api";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import ActivityIndicator from "../ui/activity-indicator";
|
import ActivityIndicator from "../indicators/activity-indicator";
|
||||||
import useKeyboardListener from "@/hooks/use-keyboard-listener";
|
import useKeyboardListener from "@/hooks/use-keyboard-listener";
|
||||||
import { Recording } from "@/types/record";
|
import { Recording } from "@/types/record";
|
||||||
import { Preview } from "@/types/preview";
|
import { Preview } from "@/types/preview";
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
import WebRtcPlayer from "./WebRTCPlayer";
|
import WebRtcPlayer from "./WebRTCPlayer";
|
||||||
import { CameraConfig } from "@/types/frigateConfig";
|
import { CameraConfig } from "@/types/frigateConfig";
|
||||||
import AutoUpdatingCameraImage from "../camera/AutoUpdatingCameraImage";
|
import AutoUpdatingCameraImage from "../camera/AutoUpdatingCameraImage";
|
||||||
import ActivityIndicator from "../ui/activity-indicator";
|
import ActivityIndicator from "../indicators/activity-indicator";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import MSEPlayer from "./MsePlayer";
|
import MSEPlayer from "./MsePlayer";
|
||||||
import JSMpegPlayer from "./JSMpegPlayer";
|
import JSMpegPlayer from "./JSMpegPlayer";
|
||||||
import { MdCircle, MdLeakAdd } from "react-icons/md";
|
import { MdCircle } from "react-icons/md";
|
||||||
import { BsSoundwave } from "react-icons/bs";
|
|
||||||
import Chip from "../Chip";
|
|
||||||
import useCameraActivity from "@/hooks/use-camera-activity";
|
import useCameraActivity from "@/hooks/use-camera-activity";
|
||||||
import { useRecordingsState } from "@/api/ws";
|
import { useRecordingsState } from "@/api/ws";
|
||||||
import { LivePlayerMode } from "@/types/live";
|
import { LivePlayerMode } from "@/types/live";
|
||||||
import useCameraLiveMode from "@/hooks/use-camera-live-mode";
|
import useCameraLiveMode from "@/hooks/use-camera-live-mode";
|
||||||
import { isDesktop } from "react-device-detect";
|
import { isDesktop } from "react-device-detect";
|
||||||
|
import CameraActivityIndicator from "../indicators/CameraActivityIndicator";
|
||||||
|
|
||||||
type LivePlayerProps = {
|
type LivePlayerProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
@ -159,35 +158,19 @@ export default function LivePlayer({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="absolute flex left-2 top-2 gap-2">
|
<div className="absolute right-2 bottom-2 w-[40px]">
|
||||||
<Chip
|
{(activeMotion ||
|
||||||
in={activeMotion}
|
(cameraConfig.audio.enabled_in_config && activeAudio)) && (
|
||||||
className={`bg-gradient-to-br from-gray-400 to-gray-500 bg-gray-500`}
|
<CameraActivityIndicator />
|
||||||
>
|
|
||||||
<MdLeakAdd className="size-4 text-motion" />
|
|
||||||
<div className="hidden md:block ml-1 text-white text-xs">Motion</div>
|
|
||||||
</Chip>
|
|
||||||
|
|
||||||
{cameraConfig.audio.enabled_in_config && (
|
|
||||||
<Chip
|
|
||||||
in={activeAudio}
|
|
||||||
className={`bg-gradient-to-br from-gray-400 to-gray-500 bg-gray-500`}
|
|
||||||
>
|
|
||||||
<BsSoundwave className="size-4 text-audio" />
|
|
||||||
<div className="hidden md:block ml-1 text-white text-xs">Sound</div>
|
|
||||||
</Chip>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isDesktop && (
|
{isDesktop && (
|
||||||
<Chip className="absolute right-2 top-2 bg-gradient-to-br from-gray-400 to-gray-500 bg-gray-500">
|
<div className="absolute right-2 top-2 size-4">
|
||||||
{recording == "ON" && (
|
{recording == "ON" && (
|
||||||
<MdCircle className="size-2 drop-shadow-md shadow-danger text-danger" />
|
<MdCircle className="size-2 drop-shadow-md shadow-danger text-danger animate-pulse" />
|
||||||
)}
|
)}
|
||||||
<div className="ml-1 capitalize text-white text-xs">
|
</div>
|
||||||
{cameraConfig.name.replaceAll("_", " ")}
|
|
||||||
</div>
|
|
||||||
</Chip>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -14,7 +14,7 @@ import TimeAgo from "../dynamic/TimeAgo";
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import { isFirefox, isMobile, isSafari } from "react-device-detect";
|
import { isFirefox, isMobile, isSafari } from "react-device-detect";
|
||||||
import Chip from "../Chip";
|
import Chip from "@/components/indicators/Chip";
|
||||||
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
||||||
import useImageLoaded from "@/hooks/use-image-loaded";
|
import useImageLoaded from "@/hooks/use-image-loaded";
|
||||||
import { Skeleton } from "../ui/skeleton";
|
import { Skeleton } from "../ui/skeleton";
|
||||||
|
@ -57,7 +57,7 @@ import {
|
|||||||
TooltipContent,
|
TooltipContent,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import ActivityIndicator from "../ui/activity-indicator";
|
import ActivityIndicator from "../indicators/activity-indicator";
|
||||||
|
|
||||||
type SettingsNavItemsProps = {
|
type SettingsNavItemsProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
|
@ -4,7 +4,7 @@ import { configureMonacoYaml } from "monaco-yaml";
|
|||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { useApiHost } from "@/api";
|
import { useApiHost } from "@/api";
|
||||||
import Heading from "@/components/ui/heading";
|
import Heading from "@/components/ui/heading";
|
||||||
import ActivityIndicator from "@/components/ui/activity-indicator";
|
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import copy from "copy-to-clipboard";
|
import copy from "copy-to-clipboard";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useWs } from "@/api/ws";
|
import { useWs } from "@/api/ws";
|
||||||
import ActivityIndicator from "@/components/ui/activity-indicator";
|
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import Heading from "@/components/ui/heading";
|
import Heading from "@/components/ui/heading";
|
||||||
|
@ -2,10 +2,11 @@ import { useMemo, useRef, useState } from "react";
|
|||||||
import Heading from "@/components/ui/heading";
|
import Heading from "@/components/ui/heading";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import ActivityIndicator from "@/components/ui/activity-indicator";
|
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||||
import EventReviewTimeline from "@/components/timeline/EventReviewTimeline";
|
import EventReviewTimeline from "@/components/timeline/EventReviewTimeline";
|
||||||
import { ReviewData, ReviewSegment, ReviewSeverity } from "@/types/review";
|
import { ReviewData, ReviewSegment, ReviewSeverity } from "@/types/review";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import CameraActivityIndicator from "@/components/indicators/CameraActivityIndicator";
|
||||||
|
|
||||||
// Color data
|
// Color data
|
||||||
const colors = [
|
const colors = [
|
||||||
@ -174,6 +175,9 @@ function UIPlayground() {
|
|||||||
<p className="text-small">
|
<p className="text-small">
|
||||||
Handlebar is dragging: {isDragging ? "yes" : "no"}
|
Handlebar is dragging: {isDragging ? "yes" : "no"}
|
||||||
</p>
|
</p>
|
||||||
|
<div className="w-[40px] my-4">
|
||||||
|
<CameraActivityIndicator />
|
||||||
|
</div>
|
||||||
<p>
|
<p>
|
||||||
<Button onClick={handleZoomOut} disabled={zoomLevel === 0}>
|
<Button onClick={handleZoomOut} disabled={zoomLevel === 0}>
|
||||||
Zoom Out
|
Zoom Out
|
||||||
|
@ -4,7 +4,7 @@ import ReviewActionGroup from "@/components/filter/ReviewActionGroup";
|
|||||||
import ReviewFilterGroup from "@/components/filter/ReviewFilterGroup";
|
import ReviewFilterGroup from "@/components/filter/ReviewFilterGroup";
|
||||||
import PreviewThumbnailPlayer from "@/components/player/PreviewThumbnailPlayer";
|
import PreviewThumbnailPlayer from "@/components/player/PreviewThumbnailPlayer";
|
||||||
import EventReviewTimeline from "@/components/timeline/EventReviewTimeline";
|
import EventReviewTimeline from "@/components/timeline/EventReviewTimeline";
|
||||||
import ActivityIndicator from "@/components/ui/activity-indicator";
|
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||||
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
||||||
import { useEventUtils } from "@/hooks/use-event-utils";
|
import { useEventUtils } from "@/hooks/use-event-utils";
|
||||||
import { useScrollLockout } from "@/hooks/use-mouse-listener";
|
import { useScrollLockout } from "@/hooks/use-mouse-listener";
|
||||||
|
@ -27,6 +27,11 @@ module.exports = {
|
|||||||
animation: {
|
animation: {
|
||||||
"accordion-down": "accordion-down 0.2s ease-out",
|
"accordion-down": "accordion-down 0.2s ease-out",
|
||||||
"accordion-up": "accordion-up 0.2s ease-out",
|
"accordion-up": "accordion-up 0.2s ease-out",
|
||||||
|
move: "move 3s ease-in-out infinite",
|
||||||
|
scale1: "scale1 3s ease-in-out infinite",
|
||||||
|
scale2: "scale2 3s ease-in-out infinite",
|
||||||
|
scale3: "scale3 3s ease-in-out infinite",
|
||||||
|
scale4: "scale4 3s ease-in-out infinite",
|
||||||
},
|
},
|
||||||
aspectRatio: {
|
aspectRatio: {
|
||||||
wide: "32 / 9",
|
wide: "32 / 9",
|
||||||
@ -96,6 +101,27 @@ module.exports = {
|
|||||||
from: { height: "var(--radix-accordion-content-height)" },
|
from: { height: "var(--radix-accordion-content-height)" },
|
||||||
to: { height: 0 },
|
to: { height: 0 },
|
||||||
},
|
},
|
||||||
|
move: {
|
||||||
|
"50%": { left: "calc(100% - 7px)" },
|
||||||
|
},
|
||||||
|
scale1: {
|
||||||
|
"0%, 100%": { transform: "scale(1.3)" },
|
||||||
|
"10%, 90%": { transform: "scale(1.4)" },
|
||||||
|
"20%, 80%": { transform: "scale(1)" },
|
||||||
|
},
|
||||||
|
scale2: {
|
||||||
|
"20%, 80%": { transform: "scale(1.4)" },
|
||||||
|
"10%, 30%, 70%, 90%": { transform: "scale(1)" },
|
||||||
|
},
|
||||||
|
scale3: {
|
||||||
|
"30%, 70%": { transform: "scale(1.4)" },
|
||||||
|
"20%, 40%, 60%, 80%": { transform: "scale(1)" },
|
||||||
|
},
|
||||||
|
scale4: {
|
||||||
|
"50%": { transform: "scale(1.3)" },
|
||||||
|
"40%, 60%": { transform: "scale(1.4)" },
|
||||||
|
"30%, 70%": { transform: "scale(1)" },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
screens: {
|
screens: {
|
||||||
xs: "480px",
|
xs: "480px",
|
||||||
|
Loading…
Reference in New Issue
Block a user