Implement score filtering on Frigate+ Page (#10968)

* Fix portrait layout disappearing

* Refactor sliders

* Reuse camera filter

* Reuse label filter content

* Implement score slider including keyboard input

* Implement ability to sort frigate plus submissions
This commit is contained in:
Nicolas Mowen
2024-04-14 10:06:11 -06:00
committed by GitHub
parent b65656fa87
commit a3e2171675
9 changed files with 384 additions and 205 deletions

View File

@@ -209,7 +209,7 @@ type CameraFilterButtonProps = {
selectedCameras: string[] | undefined;
updateCameraFilter: (cameras: string[] | undefined) => void;
};
function CamerasFilterButton({
export function CamerasFilterButton({
allCameras,
groups,
selectedCameras,
@@ -227,7 +227,7 @@ function CamerasFilterButton({
size="sm"
>
<FaVideo
className={`${selectedCameras?.length == 1 ? "text-selected-foreground" : "text-secondary-foreground"}`}
className={`${(selectedCameras?.length ?? 0) >= 1 ? "text-selected-foreground" : "text-secondary-foreground"}`}
/>
<div
className={`hidden md:block ${selectedCameras?.length ? "text-selected-foreground" : "text-primary"}`}

View File

@@ -8,7 +8,6 @@ import React, {
import { useApiHost } from "@/api";
import { isCurrentHour } from "@/utils/dateUtil";
import { ReviewSegment } from "@/types/review";
import { Slider } from "../ui/slider-no-thumb";
import { getIconForLabel } from "@/utils/iconUtil";
import TimeAgo from "../dynamic/TimeAgo";
import useSWR from "swr";
@@ -23,6 +22,7 @@ import ImageLoadingIndicator from "../indicators/ImageLoadingIndicator";
import useContextMenu from "@/hooks/use-contextmenu";
import ActivityIndicator from "../indicators/activity-indicator";
import { TimeRange } from "@/types/timeline";
import { NoThumbSlider } from "../ui/slider";
type PreviewPlayerProps = {
review: ReviewSegment;
@@ -543,7 +543,7 @@ function VideoPreview({
>
<source src={relevantPreview.src} type={relevantPreview.type} />
</video>
<Slider
<NoThumbSlider
ref={sliderRef}
className="absolute inset-x-0 bottom-0 z-30"
value={[progress]}
@@ -707,7 +707,7 @@ function InProgressPreview({
src={`${apiHost}api/preview/${previewFrames[key]}/thumbnail.webp`}
onLoad={handleLoad}
/>
<Slider
<NoThumbSlider
ref={sliderRef}
className="absolute inset-x-0 bottom-0 z-30"
value={[key]}

View File

@@ -16,8 +16,8 @@ import {
MdVolumeOff,
MdVolumeUp,
} from "react-icons/md";
import { Slider } from "../ui/slider-volume";
import useKeyboardListener from "@/hooks/use-keyboard-listener";
import { VolumeSlider } from "../ui/slider";
type VideoControls = {
volume?: boolean;
@@ -154,7 +154,7 @@ export default function VideoControls({
}}
/>
{video.muted == false && (
<Slider
<VolumeSlider
className="w-20"
value={[video.volume]}
min={0}

View File

@@ -1,26 +0,0 @@
import * as React from "react";
import * as SliderPrimitive from "@radix-ui/react-slider";
import { cn } from "@/lib/utils";
const Slider = React.forwardRef<
React.ElementRef<typeof SliderPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
>(({ className, ...props }, ref) => (
<SliderPrimitive.Root
ref={ref}
className={cn(
"relative flex w-full touch-none select-none items-center",
className,
)}
{...props}
>
<SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full">
<SliderPrimitive.Range className="absolute h-full bg-blue-500" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-4 w-16 rounded-full bg-transparent -translate-y-[50%] ring-offset-transparent focus-visible:outline-none focus-visible:ring-transparent disabled:pointer-events-none disabled:opacity-50 cursor-col-resize" />
</SliderPrimitive.Root>
));
Slider.displayName = SliderPrimitive.Root.displayName;
export { Slider };

View File

@@ -1,26 +0,0 @@
import * as React from "react";
import * as SliderPrimitive from "@radix-ui/react-slider";
import { cn } from "@/lib/utils";
const Slider = React.forwardRef<
React.ElementRef<typeof SliderPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
>(({ className, ...props }, ref) => (
<SliderPrimitive.Root
ref={ref}
className={cn(
"relative flex w-full touch-none select-none items-center",
className,
)}
{...props}
>
<SliderPrimitive.Track className="relative h-1 w-full grow overflow-hidden rounded-full bg-muted">
<SliderPrimitive.Range className="absolute h-full bg-white" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-3 w-3 rounded-full bg-white ring-white focus:ring-white disabled:pointer-events-none disabled:opacity-50" />
</SliderPrimitive.Root>
));
Slider.displayName = SliderPrimitive.Root.displayName;
export { Slider };

View File

@@ -1,7 +1,7 @@
import * as React from "react"
import * as SliderPrimitive from "@radix-ui/react-slider"
import * as React from "react";
import * as SliderPrimitive from "@radix-ui/react-slider";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Slider = React.forwardRef<
React.ElementRef<typeof SliderPrimitive.Root>,
@@ -11,7 +11,7 @@ const Slider = React.forwardRef<
ref={ref}
className={cn(
"relative flex w-full touch-none select-none items-center",
className
className,
)}
{...props}
>
@@ -20,7 +20,68 @@ const Slider = React.forwardRef<
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50" />
</SliderPrimitive.Root>
))
Slider.displayName = SliderPrimitive.Root.displayName
));
Slider.displayName = SliderPrimitive.Root.displayName;
export { Slider }
const VolumeSlider = React.forwardRef<
React.ElementRef<typeof SliderPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
>(({ className, ...props }, ref) => (
<SliderPrimitive.Root
ref={ref}
className={cn(
"relative flex w-full touch-none select-none items-center",
className,
)}
{...props}
>
<SliderPrimitive.Track className="relative h-1 w-full grow overflow-hidden rounded-full bg-muted">
<SliderPrimitive.Range className="absolute h-full bg-white" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-3 w-3 rounded-full bg-white ring-white focus:ring-white disabled:pointer-events-none disabled:opacity-50" />
</SliderPrimitive.Root>
));
VolumeSlider.displayName = SliderPrimitive.Root.displayName;
const NoThumbSlider = React.forwardRef<
React.ElementRef<typeof SliderPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
>(({ className, ...props }, ref) => (
<SliderPrimitive.Root
ref={ref}
className={cn(
"relative flex w-full touch-none select-none items-center",
className,
)}
{...props}
>
<SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full">
<SliderPrimitive.Range className="absolute h-full bg-selected" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-4 w-16 rounded-full bg-transparent -translate-y-[50%] ring-offset-transparent focus-visible:outline-none focus-visible:ring-transparent disabled:pointer-events-none disabled:opacity-50 cursor-col-resize" />
</SliderPrimitive.Root>
));
NoThumbSlider.displayName = SliderPrimitive.Root.displayName;
const DualThumbSlider = React.forwardRef<
React.ElementRef<typeof SliderPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
>(({ className, ...props }, ref) => (
<SliderPrimitive.Root
ref={ref}
className={cn(
"relative flex w-full touch-none select-none items-center",
className,
)}
{...props}
>
<SliderPrimitive.Track className="relative h-1 w-full grow overflow-hidden rounded-full bg-selected/60">
<SliderPrimitive.Range className="absolute h-full bg-selected" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block size-3 rounded-full bg-selected transition-colors cursor-col-resize disabled:pointer-events-none disabled:opacity-50" />
<SliderPrimitive.Thumb className="block size-3 rounded-full bg-selected transition-colors cursor-col-resize disabled:pointer-events-none disabled:opacity-50" />
</SliderPrimitive.Root>
));
DualThumbSlider.displayName = SliderPrimitive.Root.displayName;
export { DualThumbSlider, Slider, NoThumbSlider, VolumeSlider };