mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-11 17:47:37 +03:00
black background
This commit is contained in:
parent
576f692dae
commit
34d8c93325
@ -203,6 +203,7 @@ export function MotionReviewTimeline({
|
|||||||
scrollToSegment={scrollToSegment}
|
scrollToSegment={scrollToSegment}
|
||||||
isZooming={isZooming}
|
isZooming={isZooming}
|
||||||
zoomDirection={zoomDirection}
|
zoomDirection={zoomDirection}
|
||||||
|
getRecordingAvailability={getRecordingAvailability}
|
||||||
>
|
>
|
||||||
<VirtualizedMotionSegments
|
<VirtualizedMotionSegments
|
||||||
ref={virtualizedSegmentsRef}
|
ref={virtualizedSegmentsRef}
|
||||||
|
|||||||
@ -16,6 +16,8 @@ type MotionSegmentProps = {
|
|||||||
firstHalfMotionValue: number;
|
firstHalfMotionValue: number;
|
||||||
secondHalfMotionValue: number;
|
secondHalfMotionValue: number;
|
||||||
hasRecording?: boolean;
|
hasRecording?: boolean;
|
||||||
|
prevIsNoRecording?: boolean;
|
||||||
|
nextIsNoRecording?: boolean;
|
||||||
motionOnly: boolean;
|
motionOnly: boolean;
|
||||||
showMinimap: boolean;
|
showMinimap: boolean;
|
||||||
minimapStartTime?: number;
|
minimapStartTime?: number;
|
||||||
@ -33,6 +35,8 @@ export function MotionSegment({
|
|||||||
firstHalfMotionValue,
|
firstHalfMotionValue,
|
||||||
secondHalfMotionValue,
|
secondHalfMotionValue,
|
||||||
hasRecording,
|
hasRecording,
|
||||||
|
prevIsNoRecording,
|
||||||
|
nextIsNoRecording,
|
||||||
motionOnly,
|
motionOnly,
|
||||||
showMinimap,
|
showMinimap,
|
||||||
minimapStartTime,
|
minimapStartTime,
|
||||||
@ -116,6 +120,16 @@ export function MotionSegment({
|
|||||||
return showMinimap && segmentTime === alignedMinimapEndTime;
|
return showMinimap && segmentTime === alignedMinimapEndTime;
|
||||||
}, [showMinimap, segmentTime, alignedMinimapEndTime]);
|
}, [showMinimap, segmentTime, alignedMinimapEndTime]);
|
||||||
|
|
||||||
|
// Top border: current segment has no recording, but previous segment has recordings
|
||||||
|
const isFirstSegmentWithoutRecording = useMemo(() => {
|
||||||
|
return hasRecording === false && prevIsNoRecording === false;
|
||||||
|
}, [hasRecording, prevIsNoRecording]);
|
||||||
|
|
||||||
|
// Bottom border: current segment has no recording, but next segment has recordings
|
||||||
|
const isLastSegmentWithoutRecording = useMemo(() => {
|
||||||
|
return hasRecording === false && nextIsNoRecording === false;
|
||||||
|
}, [hasRecording, nextIsNoRecording]);
|
||||||
|
|
||||||
const firstMinimapSegmentRef = useRef<HTMLDivElement>(null);
|
const firstMinimapSegmentRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -178,16 +192,17 @@ export function MotionSegment({
|
|||||||
segmentClasses,
|
segmentClasses,
|
||||||
severity[0] && "bg-gradient-to-r",
|
severity[0] && "bg-gradient-to-r",
|
||||||
severity[0] && severityColorsBg[severity[0]],
|
severity[0] && severityColorsBg[severity[0]],
|
||||||
// TODO: will update this for 0.17
|
hasRecording == false && "bg-background",
|
||||||
false &&
|
|
||||||
hasRecording == false &&
|
|
||||||
firstHalfMotionValue == 0 &&
|
|
||||||
secondHalfMotionValue == 0 &&
|
|
||||||
"bg-slashes",
|
|
||||||
)}
|
)}
|
||||||
onClick={segmentClick}
|
onClick={segmentClick}
|
||||||
onTouchEnd={(event) => handleTouchStart(event, segmentClick)}
|
onTouchEnd={(event) => handleTouchStart(event, segmentClick)}
|
||||||
>
|
>
|
||||||
|
{isFirstSegmentWithoutRecording && (
|
||||||
|
<div className="absolute -top-[1px] left-0 right-0 h-[1px] bg-primary-variant/50" />
|
||||||
|
)}
|
||||||
|
{isLastSegmentWithoutRecording && (
|
||||||
|
<div className="absolute bottom-[0px] left-0 right-0 h-[1px] bg-primary-variant/50" />
|
||||||
|
)}
|
||||||
{!motionOnly && (
|
{!motionOnly && (
|
||||||
<>
|
<>
|
||||||
{showMinimap && (
|
{showMinimap && (
|
||||||
@ -218,45 +233,47 @@ export function MotionSegment({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="absolute left-1/2 z-10 h-[8px] w-[20px] -translate-x-1/2 transform cursor-pointer md:w-[40px]">
|
{hasRecording && (
|
||||||
<div className="mb-[1px] flex w-[20px] flex-row justify-center pt-[1px] md:w-[40px]">
|
<div className="absolute left-1/2 z-10 h-[8px] w-[20px] -translate-x-1/2 transform cursor-pointer md:w-[40px]">
|
||||||
<div className="mb-[1px] flex justify-center">
|
<div className="mb-[1px] flex w-[20px] flex-row justify-center pt-[1px] md:w-[40px]">
|
||||||
<div
|
<div className="mb-[1px] flex justify-center">
|
||||||
key={`${segmentKey}_motion_data_1`}
|
<div
|
||||||
data-motion-value={secondHalfSegmentWidth}
|
key={`${segmentKey}_motion_data_1`}
|
||||||
className={cn(
|
data-motion-value={secondHalfSegmentWidth}
|
||||||
"h-[2px]",
|
className={cn(
|
||||||
"rounded-full",
|
"h-[2px]",
|
||||||
secondHalfSegmentWidth
|
"rounded-full",
|
||||||
? "bg-motion_review"
|
secondHalfSegmentWidth
|
||||||
: "bg-muted-foreground",
|
? "bg-motion_review"
|
||||||
)}
|
: "bg-muted-foreground",
|
||||||
style={{
|
)}
|
||||||
width: secondHalfSegmentWidth || 1,
|
style={{
|
||||||
}}
|
width: secondHalfSegmentWidth || 1,
|
||||||
></div>
|
}}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex w-[20px] flex-row justify-center pb-[1px] md:w-[40px]">
|
<div className="flex w-[20px] flex-row justify-center pb-[1px] md:w-[40px]">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div
|
<div
|
||||||
key={`${segmentKey}_motion_data_2`}
|
key={`${segmentKey}_motion_data_2`}
|
||||||
data-motion-value={firstHalfSegmentWidth}
|
data-motion-value={firstHalfSegmentWidth}
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-[2px]",
|
"h-[2px]",
|
||||||
"rounded-full",
|
"rounded-full",
|
||||||
firstHalfSegmentWidth
|
firstHalfSegmentWidth
|
||||||
? "bg-motion_review"
|
? "bg-motion_review"
|
||||||
: "bg-muted-foreground",
|
: "bg-muted-foreground",
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
width: firstHalfSegmentWidth || 1,
|
width: firstHalfSegmentWidth || 1,
|
||||||
}}
|
}}
|
||||||
></div>
|
></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -36,6 +36,7 @@ export type ReviewTimelineProps = {
|
|||||||
scrollToSegment: (segmentTime: number, ifNeeded?: boolean) => void;
|
scrollToSegment: (segmentTime: number, ifNeeded?: boolean) => void;
|
||||||
isZooming: boolean;
|
isZooming: boolean;
|
||||||
zoomDirection: TimelineZoomDirection;
|
zoomDirection: TimelineZoomDirection;
|
||||||
|
getRecordingAvailability?: (time: number) => boolean | undefined;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -61,6 +62,7 @@ export function ReviewTimeline({
|
|||||||
scrollToSegment,
|
scrollToSegment,
|
||||||
isZooming,
|
isZooming,
|
||||||
zoomDirection,
|
zoomDirection,
|
||||||
|
getRecordingAvailability,
|
||||||
children,
|
children,
|
||||||
}: ReviewTimelineProps) {
|
}: ReviewTimelineProps) {
|
||||||
const [isDraggingHandlebar, setIsDraggingHandlebar] = useState(false);
|
const [isDraggingHandlebar, setIsDraggingHandlebar] = useState(false);
|
||||||
@ -326,6 +328,25 @@ export function ReviewTimeline({
|
|||||||
}
|
}
|
||||||
}, [isDraggingHandlebar, onHandlebarDraggingChange]);
|
}, [isDraggingHandlebar, onHandlebarDraggingChange]);
|
||||||
|
|
||||||
|
const isHandlebarInNoRecordingPeriod = useMemo(() => {
|
||||||
|
if (!getRecordingAvailability || handlebarTime === undefined) return false;
|
||||||
|
|
||||||
|
// Check current segment
|
||||||
|
const currentAvailability = getRecordingAvailability(handlebarTime);
|
||||||
|
if (currentAvailability !== false) return false;
|
||||||
|
|
||||||
|
// Check if at least one adjacent segment also has no recordings
|
||||||
|
const beforeAvailability = getRecordingAvailability(
|
||||||
|
handlebarTime - segmentDuration,
|
||||||
|
);
|
||||||
|
const afterAvailability = getRecordingAvailability(
|
||||||
|
handlebarTime + segmentDuration,
|
||||||
|
);
|
||||||
|
|
||||||
|
// If current segment has no recordings AND at least one adjacent segment also has no recordings
|
||||||
|
return beforeAvailability === false || afterAvailability === false;
|
||||||
|
}, [getRecordingAvailability, handlebarTime, segmentDuration]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={timelineRef}
|
ref={timelineRef}
|
||||||
@ -380,6 +401,12 @@ export function ReviewTimeline({
|
|||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/* TODO: determine if we should keep this tooltip */}
|
||||||
|
{isHandlebarInNoRecordingPeriod && (
|
||||||
|
<div className="absolute left-1/2 top-full z-50 mt-2 -translate-x-1/2 rounded-md bg-destructive/80 px-4 py-1 text-center text-xs text-white shadow-lg">
|
||||||
|
No recordings
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{showExportHandles && (
|
{showExportHandles && (
|
||||||
|
|||||||
@ -158,6 +158,15 @@ export const VirtualizedMotionSegments = forwardRef<
|
|||||||
|
|
||||||
const hasRecording = getRecordingAvailability(segmentTime);
|
const hasRecording = getRecordingAvailability(segmentTime);
|
||||||
|
|
||||||
|
const prevSegmentTime = segmentTime + segmentDuration;
|
||||||
|
const nextSegmentTime = segmentTime - segmentDuration;
|
||||||
|
|
||||||
|
const prevHasRecording = getRecordingAvailability(prevSegmentTime);
|
||||||
|
const nextHasRecording = getRecordingAvailability(nextSegmentTime);
|
||||||
|
|
||||||
|
const prevIsNoRecording = prevHasRecording === false;
|
||||||
|
const nextIsNoRecording = nextHasRecording === false;
|
||||||
|
|
||||||
if ((!segmentMotion || overlappingReviewItems) && motionOnly) {
|
if ((!segmentMotion || overlappingReviewItems) && motionOnly) {
|
||||||
return null; // Skip rendering this segment in motion only mode
|
return null; // Skip rendering this segment in motion only mode
|
||||||
}
|
}
|
||||||
@ -177,6 +186,8 @@ export const VirtualizedMotionSegments = forwardRef<
|
|||||||
firstHalfMotionValue={firstHalfMotionValue}
|
firstHalfMotionValue={firstHalfMotionValue}
|
||||||
secondHalfMotionValue={secondHalfMotionValue}
|
secondHalfMotionValue={secondHalfMotionValue}
|
||||||
hasRecording={hasRecording}
|
hasRecording={hasRecording}
|
||||||
|
prevIsNoRecording={prevIsNoRecording}
|
||||||
|
nextIsNoRecording={nextIsNoRecording}
|
||||||
segmentDuration={segmentDuration}
|
segmentDuration={segmentDuration}
|
||||||
segmentTime={segmentTime}
|
segmentTime={segmentTime}
|
||||||
timestampSpread={timestampSpread}
|
timestampSpread={timestampSpread}
|
||||||
|
|||||||
@ -44,7 +44,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
backgroundImage: {
|
backgroundImage: {
|
||||||
slashes:
|
slashes:
|
||||||
"repeating-linear-gradient(45deg, hsl(var(--primary-variant) / 0.2), hsl(var(--primary-variant) / 0.2) 2px, transparent 2px, transparent 8px)",
|
"repeating-linear-gradient(135deg, hsl(var(--primary-variant) / 0.3), hsl(var(--primary-variant) / 0.3) 2px, transparent 2px, transparent 8px), linear-gradient(to right, hsl(var(--background)), hsl(var(--background)))",
|
||||||
},
|
},
|
||||||
colors: {
|
colors: {
|
||||||
border: "hsl(var(--border))",
|
border: "hsl(var(--border))",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user