mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-12-06 13:34:13 +03:00
UI tweaks (#20675)
* spacing tweaks and add link to explore for plate * clear selected objects when changing cameras * plate link and spacing in object lifecycle * set tabindex to prevent tooltip from showing on reopen * show month and day in object lifecycle timestamp
This commit is contained in:
parent
2c480b9a89
commit
840d567d22
@ -41,7 +41,7 @@ import {
|
|||||||
ContextMenuItem,
|
ContextMenuItem,
|
||||||
ContextMenuTrigger,
|
ContextMenuTrigger,
|
||||||
} from "@/components/ui/context-menu";
|
} from "@/components/ui/context-menu";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import { ObjectPath } from "./ObjectPath";
|
import { ObjectPath } from "./ObjectPath";
|
||||||
import { getLifecycleItemDescription } from "@/utils/lifecycleUtil";
|
import { getLifecycleItemDescription } from "@/utils/lifecycleUtil";
|
||||||
import { IoPlayCircleOutline } from "react-icons/io5";
|
import { IoPlayCircleOutline } from "react-icons/io5";
|
||||||
@ -289,10 +289,10 @@ export default function ObjectLifecycle({
|
|||||||
timezone: config.ui.timezone,
|
timezone: config.ui.timezone,
|
||||||
date_format:
|
date_format:
|
||||||
config.ui.time_format == "24hour"
|
config.ui.time_format == "24hour"
|
||||||
? t("time.formattedTimestampHourMinuteSecond.24hour", {
|
? t("time.formattedTimestamp.24hour", {
|
||||||
ns: "common",
|
ns: "common",
|
||||||
})
|
})
|
||||||
: t("time.formattedTimestampHourMinuteSecond.12hour", {
|
: t("time.formattedTimestamp.12hour", {
|
||||||
ns: "common",
|
ns: "common",
|
||||||
}),
|
}),
|
||||||
time_style: "medium",
|
time_style: "medium",
|
||||||
@ -305,10 +305,10 @@ export default function ObjectLifecycle({
|
|||||||
timezone: config.ui.timezone,
|
timezone: config.ui.timezone,
|
||||||
date_format:
|
date_format:
|
||||||
config.ui.time_format == "24hour"
|
config.ui.time_format == "24hour"
|
||||||
? t("time.formattedTimestampHourMinuteSecond.24hour", {
|
? t("time.formattedTimestamp.24hour", {
|
||||||
ns: "common",
|
ns: "common",
|
||||||
})
|
})
|
||||||
: t("time.formattedTimestampHourMinuteSecond.12hour", {
|
: t("time.formattedTimestamp.12hour", {
|
||||||
ns: "common",
|
ns: "common",
|
||||||
}),
|
}),
|
||||||
time_style: "medium",
|
time_style: "medium",
|
||||||
@ -412,6 +412,7 @@ export default function ObjectLifecycle({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
|
<span tabIndex={0} className="sr-only" />
|
||||||
{!fullscreen && (
|
{!fullscreen && (
|
||||||
<div className={cn("flex items-center gap-2")}>
|
<div className={cn("flex items-center gap-2")}>
|
||||||
<Button
|
<Button
|
||||||
@ -649,10 +650,15 @@ export default function ObjectLifecycle({
|
|||||||
</span>
|
</span>
|
||||||
{event.data?.recognized_license_plate && (
|
{event.data?.recognized_license_plate && (
|
||||||
<>
|
<>
|
||||||
·{" "}
|
<span className="text-secondary-foreground">·</span>
|
||||||
<span className="text-sm text-secondary-foreground">
|
<div className="text-sm text-secondary-foreground">
|
||||||
|
<Link
|
||||||
|
to={`/explore?recognized_license_plate=${event.data.recognized_license_plate}`}
|
||||||
|
className="text-sm"
|
||||||
|
>
|
||||||
{event.data.recognized_license_plate}
|
{event.data.recognized_license_plate}
|
||||||
</span>
|
</Link>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -832,10 +838,12 @@ function LifecycleIconRow({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex w-full flex-row justify-between">
|
<div className="ml-2 flex w-full min-w-0 flex-1">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div>{getLifecycleItemDescription(item)}</div>
|
<div className="text-md flex items-start break-words text-left">
|
||||||
<div className="mt-1 flex flex-wrap items-center gap-2 text-sm text-secondary-foreground md:gap-5">
|
{getLifecycleItemDescription(item)}
|
||||||
|
</div>
|
||||||
|
<div className="mt-1 flex flex-wrap items-center gap-2 text-xs text-secondary-foreground md:gap-5">
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<span className="text-primary-variant">
|
<span className="text-primary-variant">
|
||||||
{t("objectLifecycle.lifecycleItemDesc.header.ratio")}
|
{t("objectLifecycle.lifecycleItemDesc.header.ratio")}
|
||||||
@ -893,8 +901,9 @@ function LifecycleIconRow({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div className={cn("p-1 text-sm")}>{formattedEventTimestamp}</div>
|
<div className="ml-3 flex-shrink-0 px-1 text-right text-xs text-primary-variant">
|
||||||
|
<div className="whitespace-nowrap">{formattedEventTimestamp}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import EventMenu from "@/components/timeline/EventMenu";
|
|||||||
import { FrigatePlusDialog } from "@/components/overlay/dialog/FrigatePlusDialog";
|
import { FrigatePlusDialog } from "@/components/overlay/dialog/FrigatePlusDialog";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
type DetailStreamProps = {
|
type DetailStreamProps = {
|
||||||
reviewItems?: ReviewSegment[];
|
reviewItems?: ReviewSegment[];
|
||||||
@ -499,17 +500,24 @@ function EventList({
|
|||||||
}}
|
}}
|
||||||
role="button"
|
role="button"
|
||||||
>
|
>
|
||||||
|
<div className="flex gap-2">
|
||||||
<span className="capitalize">{label}</span>
|
<span className="capitalize">{label}</span>
|
||||||
{event.data?.recognized_license_plate && (
|
{event.data?.recognized_license_plate && (
|
||||||
<>
|
<>
|
||||||
·{" "}
|
<span className="text-secondary-foreground">·</span>
|
||||||
<span className="text-sm text-secondary-foreground">
|
<div className="text-sm text-secondary-foreground">
|
||||||
|
<Link
|
||||||
|
to={`/explore?recognized_license_plate=${event.data.recognized_license_plate}`}
|
||||||
|
className="text-sm"
|
||||||
|
>
|
||||||
{event.data.recognized_license_plate}
|
{event.data.recognized_license_plate}
|
||||||
</span>
|
</Link>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div className="mr-2 flex flex-row justify-end">
|
<div className="mr-2 flex flex-row justify-end">
|
||||||
<EventMenu
|
<EventMenu
|
||||||
event={event}
|
event={event}
|
||||||
@ -615,10 +623,11 @@ function LifecycleItem({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-full flex-row justify-between">
|
|
||||||
|
<div className="ml-0.5 flex min-w-0 flex-1">
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger>
|
<TooltipTrigger>
|
||||||
<div className="flex items-start text-left">
|
<div className="flex items-start break-words text-left">
|
||||||
{getLifecycleItemDescription(item)}
|
{getLifecycleItemDescription(item)}
|
||||||
</div>
|
</div>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
@ -638,7 +647,9 @@ function LifecycleItem({
|
|||||||
</span>
|
</span>
|
||||||
{areaPx !== undefined && areaPct !== undefined ? (
|
{areaPx !== undefined && areaPct !== undefined ? (
|
||||||
<span className="font-medium text-foreground">
|
<span className="font-medium text-foreground">
|
||||||
{areaPx} {t("pixels", { ns: "common" })} · {areaPct}%
|
{areaPx} {t("pixels", { ns: "common" })}{" "}
|
||||||
|
<span className="text-secondary-foreground">·</span>{" "}
|
||||||
|
{areaPct}%
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span>N/A</span>
|
<span>N/A</span>
|
||||||
@ -648,7 +659,10 @@ function LifecycleItem({
|
|||||||
</div>
|
</div>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<div className={cn("p-1 text-xs")}>{formattedEventTimestamp}</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="ml-3 flex-shrink-0 px-1 text-right text-xs text-primary-variant">
|
||||||
|
<div className="whitespace-nowrap">{formattedEventTimestamp}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -58,6 +58,11 @@ export function DetailStreamProvider({
|
|||||||
setAnnotationOffset(cfgOffset);
|
setAnnotationOffset(cfgOffset);
|
||||||
}, [config, camera]);
|
}, [config, camera]);
|
||||||
|
|
||||||
|
// Clear selected objects when exiting detail mode or changing cameras
|
||||||
|
useEffect(() => {
|
||||||
|
setSelectedObjectIds([]);
|
||||||
|
}, [isDetailMode, camera]);
|
||||||
|
|
||||||
const value: DetailStreamContextType = {
|
const value: DetailStreamContextType = {
|
||||||
selectedObjectIds,
|
selectedObjectIds,
|
||||||
currentTime,
|
currentTime,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user