diff --git a/apps/client/src/common/hooks/useHorizontalFollowComponent.ts b/apps/client/src/common/hooks/useHorizontalFollowComponent.ts index 77888cbe6..12e66ee78 100644 --- a/apps/client/src/common/hooks/useHorizontalFollowComponent.ts +++ b/apps/client/src/common/hooks/useHorizontalFollowComponent.ts @@ -1,4 +1,5 @@ import { RefObject, useCallback, useEffect } from 'react'; +import { EntryId } from 'ontime-types'; function scrollToComponent( componentRef: RefObject | null, @@ -26,7 +27,7 @@ interface UseHorizontalFollowComponentOptions { followRef: RefObject; scrollRef: RefObject; doFollow: boolean; - hasSelectedElement?: boolean; + selectedEventId: EntryId | null; leftOffset?: number; setScrollFlag?: (newValue: boolean) => void; } @@ -39,7 +40,7 @@ export default function useHorizontalFollowComponent({ followRef, scrollRef, doFollow, - hasSelectedElement, + selectedEventId, leftOffset = 0, setScrollFlag, }: UseHorizontalFollowComponentOptions) { @@ -52,25 +53,25 @@ export default function useHorizontalFollowComponent({ // Use requestAnimationFrame to ensure the component is fully loaded window.requestAnimationFrame(() => { scrollToComponent( - hasSelectedElement ? (followRef as RefObject) : null, + selectedEventId !== null ? (followRef as RefObject) : null, scrollRef as RefObject, leftOffset, ); setScrollFlag?.(false); }); - }, [followRef, scrollRef, doFollow, hasSelectedElement, leftOffset, setScrollFlag]); + }, [followRef, scrollRef, doFollow, leftOffset, setScrollFlag, selectedEventId]); const scrollToRefComponent = useCallback( (componentRef = followRef, containerRef = scrollRef, offset = leftOffset) => { if (containerRef.current) { scrollToComponent( - hasSelectedElement ? (componentRef as RefObject) : null, + selectedEventId !== null ? (componentRef as RefObject) : null, containerRef as RefObject, offset, ); } }, - [followRef, scrollRef, hasSelectedElement, leftOffset], + [followRef, scrollRef, leftOffset, selectedEventId], ); return scrollToRefComponent; diff --git a/apps/client/src/views/timeline/Timeline.module.scss b/apps/client/src/views/timeline/Timeline.module.scss index 10916c54d..f4b30269a 100644 --- a/apps/client/src/views/timeline/Timeline.module.scss +++ b/apps/client/src/views/timeline/Timeline.module.scss @@ -28,6 +28,13 @@ $timeline-color: color-mix(in srgb, transparent 60%, var(--background-color-over height: 100%; } +.maybeInline { + display: flex; + align-items: center; + gap: 0.5em; + flex-wrap: wrap; +} + // generate combined timeline .timelineBlock { height: $timeline-height; @@ -65,7 +72,7 @@ $timeline-color: color-mix(in srgb, transparent 60%, var(--background-color-over flex: 1; display: flex; flex-direction: column; - gap: 2rem; + gap: 1rem; padding-top: 0.25rem; padding-inline-start: 0.25rem; overflow: hidden; @@ -76,32 +83,15 @@ $timeline-color: color-mix(in srgb, transparent 60%, var(--background-color-over border-top: 2px solid var(--background-color-override, $viewer-background-color); box-shadow: 0 0.25rem 0 0 var(--color, $gray-300); + text-transform: capitalize; + white-space: normal; + &[data-status='done'] { opacity: $opacity-disabled; } &[data-status='live'] { box-shadow: 0 0.25rem 0 0 $active-red; - } -} - -.delay { - margin-top: -2rem; - margin-bottom: -1rem; -} - -.timeOverview { - padding-top: 0.25rem; - padding-inline-start: 0.25em; - text-transform: capitalize; - white-space: normal; - height: 6rem; - - &[data-status='done'] { - opacity: $opacity-disabled; - } - - &[data-status='live'] { .status { color: $active-red; } @@ -114,6 +104,22 @@ $timeline-color: color-mix(in srgb, transparent 60%, var(--background-color-over } } +.delay { + color: $delay-color; +} + +.timeOverview { + padding-top: 0.25rem; + padding-inline-start: 0.25em; + height: 3rem; +} + .cross { text-decoration: line-through; + text-decoration-thickness: 2px; + text-decoration-color: $delay-color; +} + +.separeLeft { + border-left: 1px solid var(--color, $gray-300); } diff --git a/apps/client/src/views/timeline/Timeline.tsx b/apps/client/src/views/timeline/Timeline.tsx index f5562d527..962dcc437 100644 --- a/apps/client/src/views/timeline/Timeline.tsx +++ b/apps/client/src/views/timeline/Timeline.tsx @@ -38,7 +38,7 @@ function Timeline({ firstStart, rundown, selectedEventId, totalDuration }: Timel followRef: selectedRef, scrollRef: scrollContainerRef, doFollow: autosize, - hasSelectedElement: selectedEventId !== null, + selectedEventId: selectedEventId, // No offset when hiding past events to ensure content starts at 0 leftOffset: hidePast ? 0 : screenWidth / 6, }); @@ -92,6 +92,7 @@ function Timeline({ firstStart, rundown, selectedEventId, totalDuration }: Timel colour={event.colour} delay={event.delay ?? 0} duration={event.duration} + hasLink={Boolean(event.linkStart)} left={position.left} status={statusMap[event.id]} start={event.timeStart + (event.dayOffset ?? 0) * dayInMs} diff --git a/apps/client/src/views/timeline/TimelineEntry.tsx b/apps/client/src/views/timeline/TimelineEntry.tsx index d0006e8f4..006b8bb22 100644 --- a/apps/client/src/views/timeline/TimelineEntry.tsx +++ b/apps/client/src/views/timeline/TimelineEntry.tsx @@ -16,6 +16,7 @@ interface TimelineEntryProps { colour: string; delay: number; duration: number; + hasLink: boolean; left: number; status: ProgressStatus; start: number; @@ -29,21 +30,31 @@ const formatOptions = { format24: 'HH:mm', }; -export function TimelineEntry({ colour, delay, duration, left, status, start, title, width, ref }: TimelineEntryProps) { +export function TimelineEntry({ + colour, + delay, + duration, + hasLink, + left, + status, + start, + title, + width, + ref, +}: TimelineEntryProps) { const formattedStartTime = formatTime(start, formatOptions); const formattedDuration = formatDuration(duration); const delayedStart = start + delay; const hasDelay = delay > 0; const lighterColour = alpha(colour, 0.7); - const columnClasses = cx([style.column, width < 40 && style.smallArea]); - const contentClasses = cx([style.content, width < 20 && style.hide]); const showTitle = width > 25; + const smallArea = width < 40; return (
{status === 'live' ? :
}
-
{formattedStartTime}
- {hasDelay &&
{formatTime(delayedStart, formatOptions)}
} - {showTitle &&
{title}
} -
-
- {status !== 'done' && ( +
+
{formattedStartTime}
+ {hasDelay &&
{formatTime(delayedStart, formatOptions)}
} + {smallArea && } +
+ {showTitle && ( <> -
{formattedDuration}
- + {!smallArea && } +
{title}
)}
+
+ {status !== 'done' &&
{formattedDuration}
} +
); }