Compare commits

..

No commits in common. "24a1874225cf6260136c9f5f768af3a013e99603" and "c61bb8f8ae9bd955ecff95af1d0b099be9cdb6b7" have entirely different histories.

16 changed files with 99 additions and 103 deletions

View File

@ -50,27 +50,6 @@ export function AnimatedEventCard({
fetchPreviews: !currentHour, fetchPreviews: !currentHour,
}); });
const tooltipText = useMemo(() => {
if (event?.data?.metadata?.title) {
return event.data.metadata.title;
}
return (
`${[
...new Set([
...(event.data.objects || []),
...(event.data.sub_labels || []),
...(event.data.audio || []),
]),
]
.filter((item) => item !== undefined && !item.includes("-verified"))
.map((text) => text.charAt(0).toUpperCase() + text.substring(1))
.sort()
.join(", ")
.replaceAll("-verified", "")} ` + t("detected")
);
}, [event, t]);
// visibility // visibility
const [windowVisible, setWindowVisible] = useState(true); const [windowVisible, setWindowVisible] = useState(true);
@ -241,7 +220,20 @@ export function AnimatedEventCard({
)} )}
</div> </div>
</TooltipTrigger> </TooltipTrigger>
<TooltipContent>{tooltipText}</TooltipContent> <TooltipContent>
{`${[
...new Set([
...(event.data.objects || []),
...(event.data.sub_labels || []),
...(event.data.audio || []),
]),
]
.filter((item) => item !== undefined && !item.includes("-verified"))
.map((text) => text.charAt(0).toUpperCase() + text.substring(1))
.sort()
.join(", ")
.replaceAll("-verified", "")} ` + t("detected")}
</TooltipContent>
</Tooltip> </Tooltip>
); );
} }

View File

@ -355,7 +355,9 @@ export default function LiveContextMenu({
<div <div
className="flex w-full cursor-pointer items-center justify-start gap-2" className="flex w-full cursor-pointer items-center justify-start gap-2"
onClick={ onClick={
isEnabled ? () => navigate(`?debug=true#${camera}`) : undefined isEnabled
? () => navigate(`/settings?page=debug&camera=${camera}`)
: undefined
} }
> >
<div className="text-primary"> <div className="text-primary">

View File

@ -222,7 +222,7 @@ export function MobilePageHeader({
type MobilePageTitleProps = React.HTMLAttributes<HTMLHeadingElement>; type MobilePageTitleProps = React.HTMLAttributes<HTMLHeadingElement>;
export function MobilePageTitle({ className, ...props }: MobilePageTitleProps) { export function MobilePageTitle({ className, ...props }: MobilePageTitleProps) {
return <h2 className={cn("text-lg", className)} {...props} />; return <h2 className={cn("text-lg font-semibold", className)} {...props} />;
} }
type MobilePageDescriptionProps = React.HTMLAttributes<HTMLParagraphElement>; type MobilePageDescriptionProps = React.HTMLAttributes<HTMLParagraphElement>;

View File

@ -42,7 +42,7 @@ export default function RoleChangeDialog({
<Dialog open={show} onOpenChange={onCancel}> <Dialog open={show} onOpenChange={onCancel}>
<DialogContent className="sm:max-w-[425px]"> <DialogContent className="sm:max-w-[425px]">
<DialogHeader> <DialogHeader>
<DialogTitle className="text-xl"> <DialogTitle className="text-xl font-semibold">
{t("users.dialog.changeRole.title")} {t("users.dialog.changeRole.title")}
</DialogTitle> </DialogTitle>
<DialogDescription> <DialogDescription>

View File

@ -1170,7 +1170,11 @@ export function ObjectSnapshotTab({
<Card className="p-1 text-sm md:p-2"> <Card className="p-1 text-sm md:p-2">
<CardContent className="flex flex-col items-center justify-between gap-3 p-2 md:flex-row"> <CardContent className="flex flex-col items-center justify-between gap-3 p-2 md:flex-row">
<div className={cn("flex flex-col space-y-3")}> <div className={cn("flex flex-col space-y-3")}>
<div className={"text-lg leading-none"}> <div
className={
"text-lg font-semibold leading-none tracking-tight"
}
>
{t("explore.plus.submitToPlus.label")} {t("explore.plus.submitToPlus.label")}
</div> </div>
<div className="text-sm text-muted-foreground"> <div className="text-sm text-muted-foreground">

View File

@ -1,7 +1,7 @@
import * as React from "react"; import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"; import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils"
const alertVariants = cva( const alertVariants = cva(
"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
@ -16,8 +16,8 @@ const alertVariants = cva(
defaultVariants: { defaultVariants: {
variant: "default", variant: "default",
}, },
}, }
); )
const Alert = React.forwardRef< const Alert = React.forwardRef<
HTMLDivElement, HTMLDivElement,
@ -29,8 +29,8 @@ const Alert = React.forwardRef<
className={cn(alertVariants({ variant }), className)} className={cn(alertVariants({ variant }), className)}
{...props} {...props}
/> />
)); ))
Alert.displayName = "Alert"; Alert.displayName = "Alert"
const AlertTitle = React.forwardRef< const AlertTitle = React.forwardRef<
HTMLParagraphElement, HTMLParagraphElement,
@ -38,11 +38,11 @@ const AlertTitle = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<h5 <h5
ref={ref} ref={ref}
className={cn("mb-1 font-medium leading-none", className)} className={cn("mb-1 font-medium leading-none tracking-tight", className)}
{...props} {...props}
/> />
)); ))
AlertTitle.displayName = "AlertTitle"; AlertTitle.displayName = "AlertTitle"
const AlertDescription = React.forwardRef< const AlertDescription = React.forwardRef<
HTMLParagraphElement, HTMLParagraphElement,
@ -53,7 +53,7 @@ const AlertDescription = React.forwardRef<
className={cn("text-sm [&_p]:leading-relaxed", className)} className={cn("text-sm [&_p]:leading-relaxed", className)}
{...props} {...props}
/> />
)); ))
AlertDescription.displayName = "AlertDescription"; AlertDescription.displayName = "AlertDescription"
export { Alert, AlertTitle, AlertDescription }; export { Alert, AlertTitle, AlertDescription }

View File

@ -1,6 +1,6 @@
import * as React from "react"; import * as React from "react"
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils"
const Card = React.forwardRef< const Card = React.forwardRef<
HTMLDivElement, HTMLDivElement,
@ -10,12 +10,12 @@ const Card = React.forwardRef<
ref={ref} ref={ref}
className={cn( className={cn(
"rounded-lg border bg-card text-card-foreground shadow-sm", "rounded-lg border bg-card text-card-foreground shadow-sm",
className, className
)} )}
{...props} {...props}
/> />
)); ))
Card.displayName = "Card"; Card.displayName = "Card"
const CardHeader = React.forwardRef< const CardHeader = React.forwardRef<
HTMLDivElement, HTMLDivElement,
@ -26,8 +26,8 @@ const CardHeader = React.forwardRef<
className={cn("flex flex-col space-y-1.5 p-6", className)} className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props} {...props}
/> />
)); ))
CardHeader.displayName = "CardHeader"; CardHeader.displayName = "CardHeader"
const CardTitle = React.forwardRef< const CardTitle = React.forwardRef<
HTMLParagraphElement, HTMLParagraphElement,
@ -35,11 +35,14 @@ const CardTitle = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<h3 <h3
ref={ref} ref={ref}
className={cn("text-2xl font-semibold leading-none", className)} className={cn(
"text-2xl font-semibold leading-none tracking-tight",
className
)}
{...props} {...props}
/> />
)); ))
CardTitle.displayName = "CardTitle"; CardTitle.displayName = "CardTitle"
const CardDescription = React.forwardRef< const CardDescription = React.forwardRef<
HTMLParagraphElement, HTMLParagraphElement,
@ -50,16 +53,16 @@ const CardDescription = React.forwardRef<
className={cn("text-sm text-muted-foreground", className)} className={cn("text-sm text-muted-foreground", className)}
{...props} {...props}
/> />
)); ))
CardDescription.displayName = "CardDescription"; CardDescription.displayName = "CardDescription"
const CardContent = React.forwardRef< const CardContent = React.forwardRef<
HTMLDivElement, HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} /> <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
)); ))
CardContent.displayName = "CardContent"; CardContent.displayName = "CardContent"
const CardFooter = React.forwardRef< const CardFooter = React.forwardRef<
HTMLDivElement, HTMLDivElement,
@ -70,14 +73,7 @@ const CardFooter = React.forwardRef<
className={cn("flex items-center p-6 pt-0", className)} className={cn("flex items-center p-6 pt-0", className)}
{...props} {...props}
/> />
)); ))
CardFooter.displayName = "CardFooter"; CardFooter.displayName = "CardFooter"
export { export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
Card,
CardHeader,
CardFooter,
CardTitle,
CardDescription,
CardContent,
};

View File

@ -149,7 +149,10 @@ const DialogTitle = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<DialogPrimitive.Title <DialogPrimitive.Title
ref={ref} ref={ref}
className={cn("text-lg font-semibold leading-none", className)} className={cn(
"text-lg font-semibold leading-none tracking-tight",
className,
)}
{...props} {...props}
/> />
)); ));

View File

@ -85,7 +85,10 @@ const DrawerTitle = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<DrawerPrimitive.Title <DrawerPrimitive.Title
ref={ref} ref={ref}
className={cn("text-lg font-semibold leading-none", className)} className={cn(
"text-lg font-semibold leading-none tracking-tight",
className,
)}
{...props} {...props}
/> />
)); ));

View File

@ -14,7 +14,12 @@ const Heading = ({
switch (as) { switch (as) {
case "h1": case "h1":
return ( return (
<h1 className={cn("scroll-m-20 text-3xl font-extrabold", className)}> <h1
className={cn(
"scroll-m-20 text-3xl font-extrabold tracking-tight",
className
)}
>
{children} {children}
</h1> </h1>
); );
@ -22,8 +27,8 @@ const Heading = ({
return ( return (
<h2 <h2
className={cn( className={cn(
"mb-3 scroll-m-20 text-3xl font-semibold transition-colors first:mt-0", "scroll-m-20 text-3xl font-semibold tracking-tight transition-colors first:mt-0 mb-3",
className, className
)} )}
> >
{children} {children}
@ -31,19 +36,34 @@ const Heading = ({
); );
case "h3": case "h3":
return ( return (
<h3 className={cn("mb-3 scroll-m-20 text-2xl font-medium", className)}> <h3
className={cn(
"scroll-m-20 text-2xl font-semibold tracking-tight mb-3",
className
)}
>
{children} {children}
</h3> </h3>
); );
case "h4": case "h4":
return ( return (
<h4 className={cn("scroll-m-20 text-xl font-medium", className)}> <h4
className={cn(
"scroll-m-20 text-xl font-semibold tracking-tight",
className
)}
>
{children} {children}
</h4> </h4>
); );
default: default:
return ( return (
<h1 className={cn("scroll-m-20 text-3xl font-extrabold", className)}> <h1
className={cn(
"scroll-m-20 text-3xl font-extrabold tracking-tight",
className
)}
>
{children} {children}
</h1> </h1>
); );

View File

@ -112,8 +112,7 @@ export function useSearchEffect(
callback: (value: string) => boolean, callback: (value: string) => boolean,
) { ) {
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const [searchParams, setSearchParams] = useSearchParams();
const [searchParams] = useSearchParams();
const param = useMemo(() => { const param = useMemo(() => {
const param = searchParams.get(key); const param = searchParams.get(key);
@ -133,17 +132,7 @@ export function useSearchEffect(
const remove = callback(param[1]); const remove = callback(param[1]);
if (remove) { if (remove) {
navigate(location.pathname + location.hash, { setSearchParams(undefined, { state: location.state, replace: true });
state: location.state,
replace: true,
});
} }
}, [ }, [param, location.state, callback, setSearchParams]);
param,
location.state,
location.pathname,
location.hash,
callback,
navigate,
]);
} }

View File

@ -292,7 +292,7 @@ export default function Settings() {
<Logo className="h-8" /> <Logo className="h-8" />
</div> </div>
<div className="flex flex-row text-center"> <div className="flex flex-row text-center">
<h2 className="ml-2 text-lg"> <h2 className="ml-2 text-lg font-semibold">
{t("menu.settings", { ns: "common" })} {t("menu.settings", { ns: "common" })}
</h2> </h2>
</div> </div>

View File

@ -30,7 +30,7 @@ type FrigateObjectState = {
}; };
export interface FrigateReview { export interface FrigateReview {
type: "new" | "update" | "end" | "genai"; type: "new" | "update" | "end";
before: ReviewSegment; before: ReviewSegment;
after: ReviewSegment; after: ReviewSegment;
} }

View File

@ -111,7 +111,6 @@ import { Trans, useTranslation } from "react-i18next";
import { useDocDomain } from "@/hooks/use-doc-domain"; import { useDocDomain } from "@/hooks/use-doc-domain";
import PtzControlPanel from "@/components/overlay/PtzControlPanel"; import PtzControlPanel from "@/components/overlay/PtzControlPanel";
import ObjectSettingsView from "../settings/ObjectSettingsView"; import ObjectSettingsView from "../settings/ObjectSettingsView";
import { useSearchEffect } from "@/hooks/use-overlay-state";
type LiveCameraViewProps = { type LiveCameraViewProps = {
config?: FrigateConfig; config?: FrigateConfig;
@ -275,14 +274,6 @@ export default function LiveCameraView({
const [showStats, setShowStats] = useState(false); const [showStats, setShowStats] = useState(false);
const [debug, setDebug] = useState(false); const [debug, setDebug] = useState(false);
useSearchEffect("debug", (value: string) => {
if (value === "true") {
setDebug(true);
}
return true;
});
const [fullResolution, setFullResolution] = useState<VideoResolutionType>({ const [fullResolution, setFullResolution] = useState<VideoResolutionType>({
width: 0, width: 0,
height: 0, height: 0,

View File

@ -114,11 +114,7 @@ export default function LiveDashboardView({
// if event is ended and was saved, update events list // if event is ended and was saved, update events list
if (eventUpdate.after.severity == "alert") { if (eventUpdate.after.severity == "alert") {
if ( if (eventUpdate.type == "end" || eventUpdate.type == "new") {
eventUpdate.type == "end" ||
eventUpdate.type == "new" ||
eventUpdate.type == "genai"
) {
setTimeout( setTimeout(
() => updateEvents(), () => updateEvents(),
eventUpdate.type == "end" ? 1000 : 6000, eventUpdate.type == "end" ? 1000 : 6000,

View File

@ -162,9 +162,9 @@ export default function ObjectSettingsView({
} }
return ( return (
<div className="mt-1 flex size-full flex-col md:flex-row"> <div className="flex size-full flex-col md:flex-row">
<Toaster position="top-center" closeButton={true} /> <Toaster position="top-center" closeButton={true} />
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0 md:w-3/12"> <div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:w-3/12">
<Heading as="h4" className="mb-2"> <Heading as="h4" className="mb-2">
{t("debug.title")} {t("debug.title")}
</Heading> </Heading>