context menu for explore summary thumbnail images

This commit is contained in:
Josh Hawkins 2024-10-22 08:13:59 -05:00
parent 2a8a1a1b1b
commit 92efc4a3dc
2 changed files with 83 additions and 38 deletions

View File

@ -18,15 +18,22 @@ import ActivityIndicator from "@/components/indicators/activity-indicator";
import { useEventUpdate } from "@/api/ws"; import { useEventUpdate } from "@/api/ws";
import { isEqual } from "lodash"; import { isEqual } from "lodash";
import TimeAgo from "@/components/dynamic/TimeAgo"; import TimeAgo from "@/components/dynamic/TimeAgo";
import SearchResultActions from "@/components/menu/SearchResultActions";
import { SearchTab } from "@/components/overlay/detail/SearchDetailDialog";
import { FrigateConfig } from "@/types/frigateConfig";
type ExploreViewProps = { type ExploreViewProps = {
searchDetail: SearchResult | undefined; searchDetail: SearchResult | undefined;
setSearchDetail: (search: SearchResult | undefined) => void; setSearchDetail: (search: SearchResult | undefined) => void;
setSimilaritySearch: (search: SearchResult) => void;
onSelectSearch: (item: SearchResult, index: number, page?: SearchTab) => void;
}; };
export default function ExploreView({ export default function ExploreView({
searchDetail, searchDetail,
setSearchDetail, setSearchDetail,
setSimilaritySearch,
onSelectSearch,
}: ExploreViewProps) { }: ExploreViewProps) {
// title // title
@ -102,6 +109,9 @@ export default function ExploreView({
isValidating={isValidating} isValidating={isValidating}
objectType={label} objectType={label}
setSearchDetail={setSearchDetail} setSearchDetail={setSearchDetail}
mutate={mutate}
setSimilaritySearch={setSimilaritySearch}
onSelectSearch={onSelectSearch}
/> />
))} ))}
</div> </div>
@ -113,6 +123,9 @@ type ThumbnailRowType = {
searchResults?: SearchResult[]; searchResults?: SearchResult[];
isValidating: boolean; isValidating: boolean;
setSearchDetail: (search: SearchResult | undefined) => void; setSearchDetail: (search: SearchResult | undefined) => void;
mutate: () => void;
setSimilaritySearch: (search: SearchResult) => void;
onSelectSearch: (item: SearchResult, index: number, page?: SearchTab) => void;
}; };
function ThumbnailRow({ function ThumbnailRow({
@ -120,6 +133,9 @@ function ThumbnailRow({
searchResults, searchResults,
isValidating, isValidating,
setSearchDetail, setSearchDetail,
mutate,
setSimilaritySearch,
onSelectSearch,
}: ThumbnailRowType) { }: ThumbnailRowType) {
const navigate = useNavigate(); const navigate = useNavigate();
@ -155,6 +171,9 @@ function ThumbnailRow({
<ExploreThumbnailImage <ExploreThumbnailImage
event={event} event={event}
setSearchDetail={setSearchDetail} setSearchDetail={setSearchDetail}
mutate={mutate}
setSimilaritySearch={setSimilaritySearch}
onSelectSearch={onSelectSearch}
/> />
</div> </div>
))} ))}
@ -184,54 +203,78 @@ function ThumbnailRow({
type ExploreThumbnailImageProps = { type ExploreThumbnailImageProps = {
event: SearchResult; event: SearchResult;
setSearchDetail: (search: SearchResult | undefined) => void; setSearchDetail: (search: SearchResult | undefined) => void;
mutate: () => void;
setSimilaritySearch: (search: SearchResult) => void;
onSelectSearch: (item: SearchResult, index: number, page?: SearchTab) => void;
}; };
function ExploreThumbnailImage({ function ExploreThumbnailImage({
event, event,
setSearchDetail, setSearchDetail,
mutate,
setSimilaritySearch,
onSelectSearch,
}: ExploreThumbnailImageProps) { }: ExploreThumbnailImageProps) {
const apiHost = useApiHost(); const apiHost = useApiHost();
const { data: config } = useSWR<FrigateConfig>("config");
const [imgRef, imgLoaded, onImgLoad] = useImageLoaded(); const [imgRef, imgLoaded, onImgLoad] = useImageLoaded();
return ( const handleFindSimilar = () => {
<> if (config?.semantic_search.enabled) {
<ImageLoadingIndicator setSimilaritySearch(event);
className="absolute inset-0" }
imgLoaded={imgLoaded} };
/>
<img const handleShowObjectLifecycle = () => {
ref={imgRef} onSelectSearch(event, 0, "object lifecycle");
className={cn( };
"absolute h-full w-full cursor-pointer rounded-lg object-cover transition-all duration-300 ease-in-out lg:rounded-2xl",
)} return (
style={ <SearchResultActions
isIOS searchResult={event}
? { findSimilar={handleFindSimilar}
WebkitUserSelect: "none", refreshResults={mutate}
WebkitTouchCallout: "none", showObjectLifecycle={handleShowObjectLifecycle}
} isContextMenu={true}
: undefined >
} <div className="relative size-full">
loading={isSafari ? "eager" : "lazy"} <ImageLoadingIndicator
draggable={false} className="absolute inset-0"
src={`${apiHost}api/events/${event.id}/thumbnail.jpg`} imgLoaded={imgLoaded}
onClick={() => setSearchDetail(event)} />
onLoad={() => { <img
onImgLoad(); ref={imgRef}
}} className={cn(
/> "absolute size-full cursor-pointer rounded-lg object-cover transition-all duration-300 ease-in-out lg:rounded-2xl",
{isDesktop && ( !imgLoaded && "invisible",
<div className="absolute bottom-1 right-1 z-10 rounded-lg bg-black/50 px-2 py-1 text-xs text-white">
{event.end_time ? (
<TimeAgo time={event.start_time * 1000} dense />
) : (
<div>
<ActivityIndicator size={10} />
</div>
)} )}
</div> style={
)} isIOS
</> ? {
WebkitUserSelect: "none",
WebkitTouchCallout: "none",
}
: undefined
}
loading={isSafari ? "eager" : "lazy"}
draggable={false}
src={`${apiHost}api/events/${event.id}/thumbnail.jpg`}
onClick={() => setSearchDetail(event)}
onLoad={onImgLoad}
alt={`${event.label} thumbnail`}
/>
{isDesktop && (
<div className="absolute bottom-1 right-1 z-10 rounded-lg bg-black/50 px-2 py-1 text-xs text-white">
{event.end_time ? (
<TimeAgo time={event.start_time * 1000} dense />
) : (
<div>
<ActivityIndicator size={10} />
</div>
)}
</div>
)}
</div>
</SearchResultActions>
); );
} }

View File

@ -489,6 +489,8 @@ export default function SearchView({
<ExploreView <ExploreView
searchDetail={searchDetail} searchDetail={searchDetail}
setSearchDetail={setSearchDetail} setSearchDetail={setSearchDetail}
setSimilaritySearch={setSimilaritySearch}
onSelectSearch={onSelectSearch}
/> />
</div> </div>
)} )}