mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-08 20:25:26 +03:00
Add ui for events
This commit is contained in:
parent
be4b570346
commit
320677fe2b
56
web/package-lock.json
generated
56
web/package-lock.json
generated
@ -23,6 +23,8 @@
|
|||||||
"@radix-ui/react-slot": "^1.0.2",
|
"@radix-ui/react-slot": "^1.0.2",
|
||||||
"@radix-ui/react-switch": "^1.0.3",
|
"@radix-ui/react-switch": "^1.0.3",
|
||||||
"@radix-ui/react-tabs": "^1.0.4",
|
"@radix-ui/react-tabs": "^1.0.4",
|
||||||
|
"@radix-ui/react-toggle": "^1.0.3",
|
||||||
|
"@radix-ui/react-toggle-group": "^1.0.4",
|
||||||
"@radix-ui/react-tooltip": "^1.0.7",
|
"@radix-ui/react-tooltip": "^1.0.7",
|
||||||
"apexcharts": "^3.45.1",
|
"apexcharts": "^3.45.1",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
@ -1800,6 +1802,60 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-toggle": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/primitive": "1.0.1",
|
||||||
|
"@radix-ui/react-primitive": "1.0.3",
|
||||||
|
"@radix-ui/react-use-controllable-state": "1.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-toggle-group": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@radix-ui/primitive": "1.0.1",
|
||||||
|
"@radix-ui/react-context": "1.0.1",
|
||||||
|
"@radix-ui/react-direction": "1.0.1",
|
||||||
|
"@radix-ui/react-primitive": "1.0.3",
|
||||||
|
"@radix-ui/react-roving-focus": "1.0.4",
|
||||||
|
"@radix-ui/react-toggle": "1.0.3",
|
||||||
|
"@radix-ui/react-use-controllable-state": "1.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-tooltip": {
|
"node_modules/@radix-ui/react-tooltip": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.7.tgz",
|
||||||
|
|||||||
@ -28,6 +28,8 @@
|
|||||||
"@radix-ui/react-slot": "^1.0.2",
|
"@radix-ui/react-slot": "^1.0.2",
|
||||||
"@radix-ui/react-switch": "^1.0.3",
|
"@radix-ui/react-switch": "^1.0.3",
|
||||||
"@radix-ui/react-tabs": "^1.0.4",
|
"@radix-ui/react-tabs": "^1.0.4",
|
||||||
|
"@radix-ui/react-toggle": "^1.0.3",
|
||||||
|
"@radix-ui/react-toggle-group": "^1.0.4",
|
||||||
"@radix-ui/react-tooltip": "^1.0.7",
|
"@radix-ui/react-tooltip": "^1.0.7",
|
||||||
"apexcharts": "^3.45.1",
|
"apexcharts": "^3.45.1",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import Logs from "@/pages/Logs";
|
|||||||
import NoMatch from "@/pages/NoMatch";
|
import NoMatch from "@/pages/NoMatch";
|
||||||
import Settings from "@/pages/Settings";
|
import Settings from "@/pages/Settings";
|
||||||
import UIPlayground from "./pages/UIPlayground";
|
import UIPlayground from "./pages/UIPlayground";
|
||||||
|
import Events from "./pages/Events";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [sheetOpen, setSheetOpen] = useState(false);
|
const [sheetOpen, setSheetOpen] = useState(false);
|
||||||
@ -35,6 +36,7 @@ function App() {
|
|||||||
>
|
>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Live />} />
|
<Route path="/" element={<Live />} />
|
||||||
|
<Route path="/events" element={<Events />} />
|
||||||
<Route path="/history" element={<History />} />
|
<Route path="/history" element={<History />} />
|
||||||
<Route path="/export" element={<Export />} />
|
<Route path="/export" element={<Export />} />
|
||||||
<Route path="/storage" element={<Storage />} />
|
<Route path="/storage" element={<Storage />} />
|
||||||
|
|||||||
59
web/src/components/ui/toggle-group.tsx
Normal file
59
web/src/components/ui/toggle-group.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"
|
||||||
|
import { VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
import { toggleVariants } from "@/components/ui/toggle"
|
||||||
|
|
||||||
|
const ToggleGroupContext = React.createContext<
|
||||||
|
VariantProps<typeof toggleVariants>
|
||||||
|
>({
|
||||||
|
size: "default",
|
||||||
|
variant: "default",
|
||||||
|
})
|
||||||
|
|
||||||
|
const ToggleGroup = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
|
||||||
|
VariantProps<typeof toggleVariants>
|
||||||
|
>(({ className, variant, size, children, ...props }, ref) => (
|
||||||
|
<ToggleGroupPrimitive.Root
|
||||||
|
ref={ref}
|
||||||
|
className={cn("flex items-center justify-center gap-1", className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ToggleGroupContext.Provider value={{ variant, size }}>
|
||||||
|
{children}
|
||||||
|
</ToggleGroupContext.Provider>
|
||||||
|
</ToggleGroupPrimitive.Root>
|
||||||
|
))
|
||||||
|
|
||||||
|
ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName
|
||||||
|
|
||||||
|
const ToggleGroupItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
|
||||||
|
VariantProps<typeof toggleVariants>
|
||||||
|
>(({ className, children, variant, size, ...props }, ref) => {
|
||||||
|
const context = React.useContext(ToggleGroupContext)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToggleGroupPrimitive.Item
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
toggleVariants({
|
||||||
|
variant: context.variant || variant,
|
||||||
|
size: context.size || size,
|
||||||
|
}),
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ToggleGroupPrimitive.Item>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName
|
||||||
|
|
||||||
|
export { ToggleGroup, ToggleGroupItem }
|
||||||
43
web/src/components/ui/toggle.tsx
Normal file
43
web/src/components/ui/toggle.tsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import * as TogglePrimitive from "@radix-ui/react-toggle"
|
||||||
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const toggleVariants = cva(
|
||||||
|
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: "bg-transparent",
|
||||||
|
outline:
|
||||||
|
"border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default: "h-10 px-3",
|
||||||
|
sm: "h-9 px-2.5",
|
||||||
|
lg: "h-11 px-5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
size: "default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const Toggle = React.forwardRef<
|
||||||
|
React.ElementRef<typeof TogglePrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
|
||||||
|
VariantProps<typeof toggleVariants>
|
||||||
|
>(({ className, variant, size, ...props }, ref) => (
|
||||||
|
<TogglePrimitive.Root
|
||||||
|
ref={ref}
|
||||||
|
className={cn(toggleVariants({ variant, size, className }))}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
|
||||||
|
Toggle.displayName = TogglePrimitive.Root.displayName
|
||||||
|
|
||||||
|
export { Toggle, toggleVariants }
|
||||||
69
web/src/pages/Events.tsx
Normal file
69
web/src/pages/Events.tsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { LuCalendar, LuFilter, LuVideo } from "react-icons/lu";
|
||||||
|
import { MdCircle } from "react-icons/md";
|
||||||
|
|
||||||
|
type ReviewSeverity = "alert" | "detection" | "significant_motion";
|
||||||
|
|
||||||
|
export default function Events() {
|
||||||
|
const [severity, setSeverity] = useState<ReviewSeverity>("alert");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="w-full flex justify-between">
|
||||||
|
<ToggleGroup
|
||||||
|
type="single"
|
||||||
|
defaultValue="alert"
|
||||||
|
size="sm"
|
||||||
|
onValueChange={(value: ReviewSeverity) => setSeverity(value)}
|
||||||
|
>
|
||||||
|
<ToggleGroupItem
|
||||||
|
className={`px-3 py-4 rounded-2xl ${
|
||||||
|
severity == "alert" ? "" : "text-gray-500"
|
||||||
|
}`}
|
||||||
|
value="alert"
|
||||||
|
aria-label="Select alerts"
|
||||||
|
>
|
||||||
|
<MdCircle className="w-2 h-2 mr-[10px] text-danger" />
|
||||||
|
Alerts
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem
|
||||||
|
className={`px-3 py-4 rounded-2xl ${
|
||||||
|
severity == "detection" ? "" : "text-gray-500"
|
||||||
|
}`}
|
||||||
|
value="detection"
|
||||||
|
aria-label="Select detections"
|
||||||
|
>
|
||||||
|
<MdCircle className="w-2 h-2 mr-[10px] text-orange-400" />
|
||||||
|
Detections
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem
|
||||||
|
className={`px-3 py-4 rounded-2xl ${
|
||||||
|
severity == "significant_motion" ? "" : "text-gray-500"
|
||||||
|
}`}
|
||||||
|
value="significant_motion"
|
||||||
|
aria-label="Select motion"
|
||||||
|
>
|
||||||
|
<MdCircle className="w-2 h-2 mr-[10px] text-yellow-400" />
|
||||||
|
Motion
|
||||||
|
</ToggleGroupItem>
|
||||||
|
</ToggleGroup>
|
||||||
|
<div>
|
||||||
|
<Button className="mx-1" variant="secondary">
|
||||||
|
<LuVideo className=" mr-[10px]" />
|
||||||
|
All Cameras
|
||||||
|
</Button>
|
||||||
|
<Button className="mx-1" variant="secondary">
|
||||||
|
<LuCalendar className=" mr-[10px]" />
|
||||||
|
Fab 13
|
||||||
|
</Button>
|
||||||
|
<Button className="mx-1" variant="secondary">
|
||||||
|
<LuFilter className=" mr-[10px]" />
|
||||||
|
Filter
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -2,8 +2,9 @@ import {
|
|||||||
LuConstruction,
|
LuConstruction,
|
||||||
LuFileUp,
|
LuFileUp,
|
||||||
LuFilm,
|
LuFilm,
|
||||||
|
LuFlag,
|
||||||
LuVideo,
|
LuVideo,
|
||||||
} from "react-icons/lu";
|
} from "react-icons/lu";
|
||||||
|
|
||||||
export const navbarLinks = [
|
export const navbarLinks = [
|
||||||
{
|
{
|
||||||
@ -14,21 +15,27 @@ export const navbarLinks = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
|
icon: LuFlag,
|
||||||
|
title: "Events",
|
||||||
|
url: "/events",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
icon: LuFilm,
|
icon: LuFilm,
|
||||||
title: "History",
|
title: "History",
|
||||||
url: "/history",
|
url: "/history",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 4,
|
||||||
icon: LuFileUp,
|
icon: LuFileUp,
|
||||||
title: "Export",
|
title: "Export",
|
||||||
url: "/export",
|
url: "/export",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 4,
|
id: 5,
|
||||||
icon: LuConstruction,
|
icon: LuConstruction,
|
||||||
title: "UI Playground",
|
title: "UI Playground",
|
||||||
url: "/playground",
|
url: "/playground",
|
||||||
dev: true,
|
dev: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user