diff --git a/apps/client/src/features/operator/Operator.module.scss b/apps/client/src/features/operator/Operator.module.scss index 6b410b5b2..7bb2c3782 100644 --- a/apps/client/src/features/operator/Operator.module.scss +++ b/apps/client/src/features/operator/Operator.module.scss @@ -18,11 +18,11 @@ padding-bottom: 95vh; } -/* a group and its events, bounds the sticky group header to its own section */ +/* a group and its events, bounds the sticky group header to its own section. + repeats the gap of the surrounding list, which no longer reaches the rows of a section */ .groupSection { display: flex; flex-direction: column; - /* the rows used to be direct children of the list, keep the gap they had */ gap: 2px; } diff --git a/apps/client/src/views/countdown/Countdown.scss b/apps/client/src/views/countdown/Countdown.scss index f72aaab84..c411f85db 100644 --- a/apps/client/src/views/countdown/Countdown.scss +++ b/apps/client/src/views/countdown/Countdown.scss @@ -103,12 +103,12 @@ $item-height: 3.5rem; padding-bottom: max(8rem, calc(5rem + env(safe-area-inset-bottom))); } - /* a subscribed group and its subscribed events, bounds the sticky header to its own section */ + /* a subscribed group and its subscribed events, bounds the sticky header to its own section. + flex rather than block so that the row margins do not collapse, keeping the spacing between + rows of a section equal to the spacing between sections */ .sub-section { display: flex; flex-direction: column; - /* flex-grow is set inline from the row count, so that the rows keep the share they had in the list */ - flex: 1 1 0; } /* scoped to the section, the select view shows the same cards in a flat list */ diff --git a/apps/client/src/views/countdown/CountdownSubscriptions.tsx b/apps/client/src/views/countdown/CountdownSubscriptions.tsx index 895621297..5ec64ebf1 100644 --- a/apps/client/src/views/countdown/CountdownSubscriptions.tsx +++ b/apps/client/src/views/countdown/CountdownSubscriptions.tsx @@ -1,6 +1,6 @@ import { MaybeNumber, OntimeEvent } from 'ontime-types'; import { dayInMs } from 'ontime-utils'; -import { RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { IoPencil } from 'react-icons/io5'; import Button from '../../common/components/buttons/Button'; @@ -112,44 +112,6 @@ export default function CountdownSubscriptions({ subscribedEvents, goToEditMode throttledHandleScroll(); }; - const renderRow = (event: CountdownTarget, rowRef: RefObject | undefined, isLive: boolean) => { - // while a group is live, surface the running event's title as the secondary line - const liveTitle = event.isGroup && event.liveEntry ? event.liveEntry.title : undefined; - const secondaryData = liveTitle ?? getPropertyValue(event, secondarySource); - const isGroupedEvent = !event.isGroup && Boolean(event.parent); - const activeEntryId = event.isGroup ? (event.liveEntry?.id ?? event.targetId) : event.id; - const isArmed = !isLive && activeEntryId === selectedEventId; - const countdownEvent = extendEventData(event, currentDay, actualStart, plannedStart, offset, mode, reportData); - const displayTitle = getPropertyValue(event, mainSource ?? 'title'); - - return ( -
-
- - -
- {event.isGroup && Group} - {displayTitle} -
- {secondaryData &&
{secondaryData}
} -
- ); - }; - return (
{sections.map((section) => { @@ -158,21 +120,56 @@ export default function CountdownSubscriptions({ subscribedEvents, goToEditMode const anchorId = section.events.find((event) => getIsLive(event.id, selectedEventId, playback))?.id ?? null; return ( -
+
{rows.map((event) => { + // while a group is live, surface the running event's title as the secondary line + const liveTitle = event.isGroup && event.liveEntry ? event.liveEntry.title : undefined; + const secondaryData = liveTitle ?? getPropertyValue(event, secondarySource); + const isGroupedEvent = !event.isGroup && Boolean(event.parent); const activeEntryId = event.isGroup ? (event.liveEntry?.id ?? event.targetId) : event.id; // a subscribed group is live when any of its children is the selected/running event const isLive = activeEntryId ? getIsLive(activeEntryId, selectedEventId, playback) : false; + const isArmed = !isLive && activeEntryId === selectedEventId; // only ever hand the ref to a single row, sharing it would null it out on the next commit const isAnchor = isLive && (anchorId === null || event.id === anchorId); const rowRef = isAnchor ? selectedRef : event.isGroup && anchorId ? stickyHeaderRef : undefined; + const countdownEvent = extendEventData( + event, + currentDay, + actualStart, + plannedStart, + offset, + mode, + reportData, + ); + const displayTitle = getPropertyValue(event, mainSource ?? 'title'); - return renderRow(event, rowRef, isLive); + return ( +
+
+ + +
+ {event.isGroup && Group} + {displayTitle} +
+ {secondaryData &&
{secondaryData}
} +
+ ); })}
);