mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-10 21:25:24 +03:00
Fix loading of images
This commit is contained in:
parent
bacf202fd4
commit
1b73917ba3
@ -7,6 +7,8 @@ import { isSafari } from "react-device-detect";
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import TimeAgo from "../dynamic/TimeAgo";
|
import TimeAgo from "../dynamic/TimeAgo";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
import useImageLoaded from "@/hooks/use-image-loaded";
|
||||||
|
import ImageLoadingIndicator from "../indicators/ImageLoadingIndicator";
|
||||||
|
|
||||||
type ReviewCardProps = {
|
type ReviewCardProps = {
|
||||||
event: ReviewSegment;
|
event: ReviewSegment;
|
||||||
@ -19,6 +21,7 @@ export default function ReviewCard({
|
|||||||
onClick,
|
onClick,
|
||||||
}: ReviewCardProps) {
|
}: ReviewCardProps) {
|
||||||
const { data: config } = useSWR<FrigateConfig>("config");
|
const { data: config } = useSWR<FrigateConfig>("config");
|
||||||
|
const [imgRef, imgLoaded, onImgLoad] = useImageLoaded();
|
||||||
const formattedDate = useFormattedTimestamp(
|
const formattedDate = useFormattedTimestamp(
|
||||||
event.start_time,
|
event.start_time,
|
||||||
config?.ui.time_format == "24hour" ? "%H:%M" : "%I:%M %p",
|
config?.ui.time_format == "24hour" ? "%H:%M" : "%I:%M %p",
|
||||||
@ -28,17 +31,23 @@ export default function ReviewCard({
|
|||||||
[event, currentTime],
|
[event, currentTime],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (event.data.objects.includes("car")) {
|
||||||
|
//console.log(`failed to load ${JSON.stringify(event)}`);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="w-full flex flex-col gap-1.5 cursor-pointer"
|
className="w-full flex flex-col gap-1.5 cursor-pointer"
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
|
<ImageLoadingIndicator className="size-full" imgLoaded={imgLoaded} />
|
||||||
<img
|
<img
|
||||||
className={`size-full rounded-lg ${isSelected ? "outline outline-3 outline-offset-1 outline-selected" : ""}`}
|
ref={imgRef}
|
||||||
|
className={`size-full rounded-lg ${isSelected ? "outline outline-3 outline-offset-1 outline-selected" : ""} ${imgLoaded ? "visible" : "invisible"}`}
|
||||||
src={`${baseUrl}${event.thumb_path.replace("/media/frigate/", "")}`}
|
src={`${baseUrl}${event.thumb_path.replace("/media/frigate/", "")}`}
|
||||||
loading={isSafari ? "eager" : "lazy"}
|
loading={isSafari ? "eager" : "lazy"}
|
||||||
onLoad={() => {
|
onLoad={() => {
|
||||||
//onImgLoad();
|
onImgLoad();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
|
|||||||
20
web/src/components/indicators/ImageLoadingIndicator.tsx
Normal file
20
web/src/components/indicators/ImageLoadingIndicator.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { isSafari } from "react-device-detect";
|
||||||
|
import { Skeleton } from "../ui/skeleton";
|
||||||
|
|
||||||
|
export default function ImageLoadingIndicator({
|
||||||
|
className,
|
||||||
|
imgLoaded,
|
||||||
|
}: {
|
||||||
|
className?: string;
|
||||||
|
imgLoaded: boolean;
|
||||||
|
}) {
|
||||||
|
if (imgLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isSafari ? (
|
||||||
|
<div className={`bg-gray-300 pointer-events-none ${className ?? ""}`} />
|
||||||
|
) : (
|
||||||
|
<Skeleton className={`pointer-events-none ${className ?? ""}`} />
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -17,9 +17,9 @@ import { isFirefox, isMobile, isSafari } from "react-device-detect";
|
|||||||
import Chip from "@/components/indicators/Chip";
|
import Chip from "@/components/indicators/Chip";
|
||||||
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
||||||
import useImageLoaded from "@/hooks/use-image-loaded";
|
import useImageLoaded from "@/hooks/use-image-loaded";
|
||||||
import { Skeleton } from "../ui/skeleton";
|
|
||||||
import { useSwipeable } from "react-swipeable";
|
import { useSwipeable } from "react-swipeable";
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
|
||||||
|
import ImageLoadingIndicator from "../indicators/ImageLoadingIndicator";
|
||||||
|
|
||||||
type PreviewPlayerProps = {
|
type PreviewPlayerProps = {
|
||||||
review: ReviewSegment;
|
review: ReviewSegment;
|
||||||
@ -187,7 +187,10 @@ export default function PreviewThumbnailPlayer({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<PreviewPlaceholder imgLoaded={imgLoaded} />
|
<ImageLoadingIndicator
|
||||||
|
className="absolute inset-0"
|
||||||
|
imgLoaded={imgLoaded}
|
||||||
|
/>
|
||||||
<div className={`${imgLoaded ? "visible" : "invisible"}`}>
|
<div className={`${imgLoaded ? "visible" : "invisible"}`}>
|
||||||
<img
|
<img
|
||||||
ref={imgRef}
|
ref={imgRef}
|
||||||
@ -700,15 +703,3 @@ function InProgressPreview({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function PreviewPlaceholder({ imgLoaded }: { imgLoaded: boolean }) {
|
|
||||||
if (imgLoaded) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isSafari ? (
|
|
||||||
<div className={`absolute inset-0 bg-gray-300 pointer-events-none`} />
|
|
||||||
) : (
|
|
||||||
<Skeleton className={`absolute inset-0 pointer-events-none`} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -277,7 +277,7 @@ export function RecordingView({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`flex h-full justify-center overflow-hidden ${isDesktop ? "" : "flex-col"}`}
|
className={`flex h-full mb-2 justify-center overflow-hidden ${isDesktop ? "" : "flex-col"}`}
|
||||||
>
|
>
|
||||||
<div className="flex flex-1 flex-wrap">
|
<div className="flex flex-1 flex-wrap">
|
||||||
<div
|
<div
|
||||||
@ -418,14 +418,20 @@ function Timeline({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-60 h-full p-4 flex flex-col gap-4 bg-secondary overflow-auto">
|
<div className="w-60 h-full p-4 flex flex-col gap-4 bg-secondary overflow-auto">
|
||||||
{mainCameraReviewItems.map((review) => (
|
{mainCameraReviewItems.map((review) => {
|
||||||
|
if (review.severity == "significant_motion") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<ReviewCard
|
<ReviewCard
|
||||||
key={review.id}
|
key={review.id}
|
||||||
event={review}
|
event={review}
|
||||||
currentTime={currentTime}
|
currentTime={currentTime}
|
||||||
onClick={() => setCurrentTime(review.start_time)}
|
onClick={() => setCurrentTime(review.start_time)}
|
||||||
/>
|
/>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user