mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-11 17:47:37 +03:00
reusable tabs component
This commit is contained in:
parent
5f4de57bc3
commit
348d40d7fd
@ -119,12 +119,6 @@ export default function SearchDetailDialog({
|
|||||||
100,
|
100,
|
||||||
);
|
);
|
||||||
|
|
||||||
// tracking details state
|
|
||||||
|
|
||||||
const [trackingTimeIndex, setTrackingTimeIndex] = useState<
|
|
||||||
number | undefined
|
|
||||||
>(undefined);
|
|
||||||
|
|
||||||
// dialog and mobile page
|
// dialog and mobile page
|
||||||
|
|
||||||
const [isOpen, setIsOpen] = useState(search != undefined);
|
const [isOpen, setIsOpen] = useState(search != undefined);
|
||||||
@ -184,6 +178,42 @@ export default function SearchDetailDialog({
|
|||||||
}
|
}
|
||||||
}, [pageToggle, searchTabs, setSearchPage]);
|
}, [pageToggle, searchTabs, setSearchPage]);
|
||||||
|
|
||||||
|
// Tabs component for reuse
|
||||||
|
const tabsComponent = (
|
||||||
|
<ScrollArea className="w-full whitespace-nowrap">
|
||||||
|
<div className="flex flex-row">
|
||||||
|
<ToggleGroup
|
||||||
|
className="*:rounded-md *:px-3 *:py-4"
|
||||||
|
type="single"
|
||||||
|
size="sm"
|
||||||
|
value={pageToggle}
|
||||||
|
onValueChange={(value: SearchTab) => {
|
||||||
|
if (value) {
|
||||||
|
setPageToggle(value);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Object.values(searchTabs).map((item) => (
|
||||||
|
<ToggleGroupItem
|
||||||
|
key={item}
|
||||||
|
className={`flex scroll-mx-10 items-center justify-between gap-2 ${page == "details" ? "last:mr-20" : ""} ${pageToggle == item ? "" : "*:text-muted-foreground"}`}
|
||||||
|
value={item}
|
||||||
|
data-nav-item={item}
|
||||||
|
aria-label={`Select ${item}`}
|
||||||
|
>
|
||||||
|
{item == "details" && <FaRegListAlt className="size-4" />}
|
||||||
|
{item == "snapshot" && <FaImage className="size-4" />}
|
||||||
|
{item == "video" && <FaVideo className="size-4" />}
|
||||||
|
{item == "tracking_details" && <PiPath className="size-4" />}
|
||||||
|
<div className="smart-capitalize">{t(`type.${item}`)}</div>
|
||||||
|
</ToggleGroupItem>
|
||||||
|
))}
|
||||||
|
</ToggleGroup>
|
||||||
|
<ScrollBar orientation="horizontal" className="h-0" />
|
||||||
|
</div>
|
||||||
|
</ScrollArea>
|
||||||
|
);
|
||||||
|
|
||||||
if (!search) {
|
if (!search) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -220,136 +250,88 @@ export default function SearchDetailDialog({
|
|||||||
</Description>
|
</Description>
|
||||||
</Header>
|
</Header>
|
||||||
{isDesktop ? (
|
{isDesktop ? (
|
||||||
<div className="flex h-full gap-4 overflow-hidden">
|
page === "tracking_details" ? (
|
||||||
<div className="scrollbar-container flex-[3] overflow-y-auto">
|
<TrackingDetails
|
||||||
{page === "snapshot" && search.has_snapshot && (
|
className="size-full"
|
||||||
<ObjectSnapshotTab
|
event={search as unknown as Event}
|
||||||
search={
|
tabs={tabsComponent}
|
||||||
{
|
/>
|
||||||
...search,
|
) : (
|
||||||
plus_id: config?.plus?.enabled
|
<div className="flex h-full gap-4 overflow-hidden">
|
||||||
? search.plus_id
|
<div className="scrollbar-container flex-[3] overflow-y-hidden">
|
||||||
: "not_enabled",
|
{page === "snapshot" && search.has_snapshot && (
|
||||||
} as unknown as Event
|
<ObjectSnapshotTab
|
||||||
}
|
search={
|
||||||
onEventUploaded={() => {
|
{
|
||||||
search.plus_id = "new_upload";
|
...search,
|
||||||
}}
|
plus_id: config?.plus?.enabled
|
||||||
/>
|
? search.plus_id
|
||||||
)}
|
: "not_enabled",
|
||||||
{page === "video" && search.has_clip && (
|
} as unknown as Event
|
||||||
<VideoTab search={search} />
|
}
|
||||||
)}
|
onEventUploaded={() => {
|
||||||
{page === "tracking_details" && (
|
search.plus_id = "new_upload";
|
||||||
<TrackingDetails
|
|
||||||
event={search as unknown as Event}
|
|
||||||
showImage={true}
|
|
||||||
showLifecycle={false}
|
|
||||||
timeIndex={trackingTimeIndex}
|
|
||||||
setTimeIndex={setTrackingTimeIndex}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{(page === "details" ||
|
|
||||||
(!search.has_snapshot && page === "snapshot") ||
|
|
||||||
(!search.has_clip && page === "video")) && (
|
|
||||||
<img
|
|
||||||
className="aspect-video select-none rounded-lg object-contain transition-opacity"
|
|
||||||
style={
|
|
||||||
isIOS
|
|
||||||
? {
|
|
||||||
WebkitUserSelect: "none",
|
|
||||||
WebkitTouchCallout: "none",
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
draggable={false}
|
|
||||||
src={`${apiHost}api/events/${search.id}/thumbnail.webp`}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-[2] flex-col gap-4 overflow-hidden">
|
|
||||||
<ScrollArea className="w-full whitespace-nowrap">
|
|
||||||
<div className="flex flex-row">
|
|
||||||
<ToggleGroup
|
|
||||||
className="*:rounded-md *:px-3 *:py-4"
|
|
||||||
type="single"
|
|
||||||
size="sm"
|
|
||||||
value={pageToggle}
|
|
||||||
onValueChange={(value: SearchTab) => {
|
|
||||||
if (value) {
|
|
||||||
setPageToggle(value);
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
>
|
|
||||||
{Object.values(searchTabs).map((item) => (
|
|
||||||
<ToggleGroupItem
|
|
||||||
key={item}
|
|
||||||
className={`flex scroll-mx-10 items-center justify-between gap-2 ${page == "details" ? "last:mr-20" : ""} ${pageToggle == item ? "" : "*:text-muted-foreground"}`}
|
|
||||||
value={item}
|
|
||||||
data-nav-item={item}
|
|
||||||
aria-label={`Select ${item}`}
|
|
||||||
>
|
|
||||||
{item == "details" && (
|
|
||||||
<FaRegListAlt className="size-4" />
|
|
||||||
)}
|
|
||||||
{item == "snapshot" && <FaImage className="size-4" />}
|
|
||||||
{item == "video" && <FaVideo className="size-4" />}
|
|
||||||
{item == "tracking_details" && (
|
|
||||||
<PiPath className="size-4" />
|
|
||||||
)}
|
|
||||||
<div className="smart-capitalize">
|
|
||||||
{t(`type.${item}`)}
|
|
||||||
</div>
|
|
||||||
</ToggleGroupItem>
|
|
||||||
))}
|
|
||||||
</ToggleGroup>
|
|
||||||
<ScrollBar orientation="horizontal" className="h-0" />
|
|
||||||
</div>
|
|
||||||
</ScrollArea>
|
|
||||||
<div className="scrollbar-container flex-1 overflow-y-auto">
|
|
||||||
{page == "details" && (
|
|
||||||
<ObjectDetailsTab
|
|
||||||
search={search}
|
|
||||||
config={config}
|
|
||||||
setSearch={setSearch}
|
|
||||||
setSimilarity={setSimilarity}
|
|
||||||
setInputFocused={setInputFocused}
|
|
||||||
showThumbnail={false}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{page == "snapshot" && (
|
{page === "video" && search.has_clip && (
|
||||||
<ObjectDetailsTab
|
<VideoTab search={search} />
|
||||||
search={search}
|
|
||||||
config={config}
|
|
||||||
setSearch={setSearch}
|
|
||||||
setSimilarity={setSimilarity}
|
|
||||||
setInputFocused={setInputFocused}
|
|
||||||
showThumbnail={false}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
{page == "video" && (
|
{(page === "details" ||
|
||||||
<ObjectDetailsTab
|
(!search.has_snapshot && page === "snapshot") ||
|
||||||
search={search}
|
(!search.has_clip && page === "video")) && (
|
||||||
config={config}
|
<img
|
||||||
setSearch={setSearch}
|
className="aspect-video select-none rounded-lg object-contain transition-opacity"
|
||||||
setSimilarity={setSimilarity}
|
style={
|
||||||
setInputFocused={setInputFocused}
|
isIOS
|
||||||
showThumbnail={false}
|
? {
|
||||||
/>
|
WebkitUserSelect: "none",
|
||||||
)}
|
WebkitTouchCallout: "none",
|
||||||
{page == "tracking_details" && (
|
}
|
||||||
<TrackingDetails
|
: undefined
|
||||||
className="w-full overflow-x-hidden"
|
}
|
||||||
event={search as unknown as Event}
|
draggable={false}
|
||||||
showImage={false}
|
src={`${apiHost}api/events/${search.id}/thumbnail.webp`}
|
||||||
showLifecycle={true}
|
|
||||||
timeIndex={trackingTimeIndex}
|
|
||||||
setTimeIndex={setTrackingTimeIndex}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex flex-[2] flex-col gap-4 overflow-hidden">
|
||||||
|
{tabsComponent}
|
||||||
|
<div className="scrollbar-container flex-1 overflow-y-auto">
|
||||||
|
{page == "details" && (
|
||||||
|
<ObjectDetailsTab
|
||||||
|
search={search}
|
||||||
|
config={config}
|
||||||
|
setSearch={setSearch}
|
||||||
|
setSimilarity={setSimilarity}
|
||||||
|
setInputFocused={setInputFocused}
|
||||||
|
showThumbnail={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{page == "snapshot" && (
|
||||||
|
<ObjectDetailsTab
|
||||||
|
search={search}
|
||||||
|
config={config}
|
||||||
|
setSearch={setSearch}
|
||||||
|
setSimilarity={setSimilarity}
|
||||||
|
setInputFocused={setInputFocused}
|
||||||
|
showThumbnail={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{page == "video" && (
|
||||||
|
<ObjectDetailsTab
|
||||||
|
search={search}
|
||||||
|
config={config}
|
||||||
|
setSearch={setSearch}
|
||||||
|
setSimilarity={setSimilarity}
|
||||||
|
setInputFocused={setInputFocused}
|
||||||
|
showThumbnail={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<ScrollArea
|
<ScrollArea
|
||||||
@ -419,10 +401,6 @@ export default function SearchDetailDialog({
|
|||||||
<TrackingDetails
|
<TrackingDetails
|
||||||
className="w-full overflow-x-hidden"
|
className="w-full overflow-x-hidden"
|
||||||
event={search as unknown as Event}
|
event={search as unknown as Event}
|
||||||
showImage={true}
|
|
||||||
showLifecycle={true}
|
|
||||||
timeIndex={trackingTimeIndex}
|
|
||||||
setTimeIndex={setTrackingTimeIndex}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user