forked from Github/frigate
UI tweaks (#13633)
* Object lifecycle and semantic search UI tweaks * prevent console errors for sheet component
This commit is contained in:
@@ -44,6 +44,7 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { AnnotationSettingsPane } from "./AnnotationSettingsPane";
|
||||
import { TooltipPortal } from "@radix-ui/react-tooltip";
|
||||
|
||||
type ObjectLifecycleProps = {
|
||||
review: ReviewSegment;
|
||||
@@ -185,7 +186,6 @@ export default function ObjectLifecycle({
|
||||
if (!mainApi || !thumbnailApi) {
|
||||
return;
|
||||
}
|
||||
thumbnailApi.scrollTo(index);
|
||||
mainApi.scrollTo(index);
|
||||
setCurrent(index);
|
||||
};
|
||||
@@ -210,18 +210,10 @@ export default function ObjectLifecycle({
|
||||
thumbnailApi.scrollTo(selected);
|
||||
};
|
||||
|
||||
const handleBottomSelect = () => {
|
||||
const selected = thumbnailApi.selectedScrollSnap();
|
||||
setCurrent(selected);
|
||||
mainApi.scrollTo(selected);
|
||||
};
|
||||
|
||||
mainApi.on("select", handleTopSelect);
|
||||
thumbnailApi.on("select", handleBottomSelect);
|
||||
mainApi.on("select", handleTopSelect).on("reInit", handleTopSelect);
|
||||
|
||||
return () => {
|
||||
mainApi.off("select", handleTopSelect);
|
||||
thumbnailApi.off("select", handleBottomSelect);
|
||||
};
|
||||
// we know that these deps are correct
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@@ -467,15 +459,22 @@ export default function ObjectLifecycle({
|
||||
<Carousel
|
||||
opts={{
|
||||
align: "center",
|
||||
containScroll: "keepSnaps",
|
||||
dragFree: true,
|
||||
}}
|
||||
className="w-full max-w-[72%] md:max-w-[85%]"
|
||||
setApi={setThumbnailApi}
|
||||
>
|
||||
<CarouselContent className="flex flex-row justify-center">
|
||||
<CarouselContent
|
||||
className={cn(
|
||||
"-ml-1 flex select-none flex-row",
|
||||
eventSequence.length > 4 ? "justify-start" : "justify-center",
|
||||
)}
|
||||
>
|
||||
{eventSequence.map((item, index) => (
|
||||
<CarouselItem
|
||||
key={index}
|
||||
className={cn("basis-1/4 cursor-pointer md:basis-[10%]")}
|
||||
className={cn("basis-1/4 cursor-pointer pl-1 md:basis-[10%]")}
|
||||
onClick={() => handleThumbnailClick(index)}
|
||||
>
|
||||
<div className="p-1">
|
||||
@@ -486,15 +485,24 @@ export default function ObjectLifecycle({
|
||||
index === current && "bg-selected",
|
||||
)}
|
||||
>
|
||||
<LifecycleIcon
|
||||
className={cn(
|
||||
"size-8",
|
||||
index === current
|
||||
? "bg-selected text-white"
|
||||
: "text-muted-foreground",
|
||||
)}
|
||||
lifecycleItem={item}
|
||||
/>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<LifecycleIcon
|
||||
className={cn(
|
||||
"size-8",
|
||||
index === current
|
||||
? "bg-selected text-white"
|
||||
: "text-muted-foreground",
|
||||
)}
|
||||
lifecycleItem={item}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent className="capitalize">
|
||||
{getLifecycleItemDescription(item)}
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
import { isDesktop, isIOS, isMobile } from "react-device-detect";
|
||||
import { Sheet, SheetContent } from "../../ui/sheet";
|
||||
import { Drawer, DrawerContent } from "../../ui/drawer";
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
} from "../../ui/sheet";
|
||||
import {
|
||||
Drawer,
|
||||
DrawerContent,
|
||||
DrawerDescription,
|
||||
DrawerHeader,
|
||||
DrawerTitle,
|
||||
} from "../../ui/drawer";
|
||||
import useSWR from "swr";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
||||
@@ -66,6 +78,9 @@ export default function ReviewDetailDialog({
|
||||
|
||||
const Overlay = isDesktop ? Sheet : Drawer;
|
||||
const Content = isDesktop ? SheetContent : DrawerContent;
|
||||
const Header = isDesktop ? SheetHeader : DrawerHeader;
|
||||
const Title = isDesktop ? SheetTitle : DrawerTitle;
|
||||
const Description = isDesktop ? SheetDescription : DrawerDescription;
|
||||
|
||||
if (!review) {
|
||||
return;
|
||||
@@ -102,6 +117,10 @@ export default function ReviewDetailDialog({
|
||||
: "max-h-[80dvh] overflow-hidden p-2 pb-4",
|
||||
)}
|
||||
>
|
||||
<Header className="sr-only">
|
||||
<Title>Review Item Details</Title>
|
||||
<Description>Review item details</Description>
|
||||
</Header>
|
||||
{pane == "overview" && (
|
||||
<div className="scrollbar-container mt-3 flex size-full flex-col gap-5 overflow-y-auto">
|
||||
<div className="flex w-full flex-row">
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
import { isDesktop, isIOS } from "react-device-detect";
|
||||
import { Sheet, SheetContent } from "../../ui/sheet";
|
||||
import { Drawer, DrawerContent } from "../../ui/drawer";
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
} from "../../ui/sheet";
|
||||
import {
|
||||
Drawer,
|
||||
DrawerContent,
|
||||
DrawerDescription,
|
||||
DrawerHeader,
|
||||
DrawerTitle,
|
||||
} from "../../ui/drawer";
|
||||
import { SearchResult } from "@/types/search";
|
||||
import useSWR from "swr";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
@@ -71,6 +83,9 @@ export default function SearchDetailDialog({
|
||||
|
||||
const Overlay = isDesktop ? Sheet : Drawer;
|
||||
const Content = isDesktop ? SheetContent : DrawerContent;
|
||||
const Header = isDesktop ? SheetHeader : DrawerHeader;
|
||||
const Title = isDesktop ? SheetTitle : DrawerTitle;
|
||||
const Description = isDesktop ? SheetDescription : DrawerDescription;
|
||||
|
||||
return (
|
||||
<Overlay
|
||||
@@ -86,6 +101,10 @@ export default function SearchDetailDialog({
|
||||
isDesktop ? "sm:max-w-xl" : "max-h-[75dvh] overflow-hidden p-2 pb-4"
|
||||
}
|
||||
>
|
||||
<Header className="sr-only">
|
||||
<Title>Tracked Object Details</Title>
|
||||
<Description>Tracked object details</Description>
|
||||
</Header>
|
||||
{search && (
|
||||
<div className="mt-3 flex size-full flex-col gap-5 md:mt-0">
|
||||
<div className="flex w-full flex-row">
|
||||
@@ -93,7 +112,7 @@ export default function SearchDetailDialog({
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<div className="text-sm text-primary/40">Label</div>
|
||||
<div className="flex flex-row items-center gap-2 text-sm capitalize">
|
||||
{getIconForLabel(search.label, "size-4 text-white")}
|
||||
{getIconForLabel(search.label, "size-4 text-primary")}
|
||||
{search.label}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user