From a220678321e3ffd243caa98bd19046d05b5373c0 Mon Sep 17 00:00:00 2001
From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
Date: Fri, 24 Oct 2025 10:17:48 -0500
Subject: [PATCH] match object lifecycle with details
---
.../overlay/detail/ObjectLifecycle.tsx | 383 +++++++++++-------
1 file changed, 239 insertions(+), 144 deletions(-)
diff --git a/web/src/components/overlay/detail/ObjectLifecycle.tsx b/web/src/components/overlay/detail/ObjectLifecycle.tsx
index d335e35c9..0f1eaadf5 100644
--- a/web/src/components/overlay/detail/ObjectLifecycle.tsx
+++ b/web/src/components/overlay/detail/ObjectLifecycle.tsx
@@ -47,6 +47,7 @@ import { getLifecycleItemDescription } from "@/utils/lifecycleUtil";
import { IoPlayCircleOutline } from "react-icons/io5";
import { useTranslation } from "react-i18next";
import { getTranslatedLabel } from "@/utils/i18n";
+import { Badge } from "@/components/ui/badge";
type ObjectLifecycleProps = {
className?: string;
@@ -355,6 +356,52 @@ export default function ObjectLifecycle({
return idx === -1 ? 0 : idx;
}, [eventSequence, timeIndex]);
+ // Calculate how far down the blue line should extend based on timeIndex
+ const calculateLineHeight = () => {
+ if (!eventSequence || eventSequence.length === 0) return 0;
+
+ const currentTime = timeIndex ?? 0;
+
+ // Find which events have been passed
+ let lastPassedIndex = -1;
+ for (let i = 0; i < eventSequence.length; i++) {
+ if (currentTime >= (eventSequence[i].timestamp ?? 0)) {
+ lastPassedIndex = i;
+ } else {
+ break;
+ }
+ }
+
+ // No events passed yet
+ if (lastPassedIndex < 0) return 0;
+
+ // All events passed
+ if (lastPassedIndex >= eventSequence.length - 1) return 100;
+
+ // Calculate percentage based on item position, not time
+ // Each item occupies an equal visual space regardless of time gaps
+ const itemPercentage = 100 / (eventSequence.length - 1);
+
+ // Find progress between current and next event for smooth transition
+ const currentEvent = eventSequence[lastPassedIndex];
+ const nextEvent = eventSequence[lastPassedIndex + 1];
+ const currentTimestamp = currentEvent.timestamp ?? 0;
+ const nextTimestamp = nextEvent.timestamp ?? 0;
+
+ // Calculate interpolation between the two events
+ const timeBetween = nextTimestamp - currentTimestamp;
+ const timeElapsed = currentTime - currentTimestamp;
+ const interpolation = timeBetween > 0 ? timeElapsed / timeBetween : 0;
+
+ // Base position plus interpolated progress to next item
+ return Math.min(
+ 100,
+ lastPassedIndex * itemPercentage + interpolation * itemPercentage,
+ );
+ };
+
+ const blueLineHeight = calculateLineHeight();
+
if (!config) {
return