diff --git a/apps/client/src/features/operator/Operator.tsx b/apps/client/src/features/operator/Operator.tsx index e594faccc..c79abe4ba 100644 --- a/apps/client/src/features/operator/Operator.tsx +++ b/apps/client/src/features/operator/Operator.tsx @@ -180,7 +180,13 @@ function Operator({ rundown, rundownMetadata, customFields, settings }: Operator return ( - + {entry.entries.map((nestedEntryId) => { const nestedEntry = rundown.entries[nestedEntryId]; if (!isOntimeEvent(nestedEntry)) { @@ -217,6 +223,7 @@ function Operator({ rundown, rundownMetadata, customFields, settings }: Operator isLinkedToLoaded={isLinkedToLoaded} isSelected={isLoaded} isPast={isPast} + groupColour={entry.colour} selectedRef={isLoaded ? selectedRef : undefined} showStart={showStart} subscribed={subscribedData} diff --git a/apps/client/src/features/operator/operator-event/OperatorEvent.module.scss b/apps/client/src/features/operator/operator-event/OperatorEvent.module.scss index d83074bcb..a8b63ccb3 100644 --- a/apps/client/src/features/operator/operator-event/OperatorEvent.module.scss +++ b/apps/client/src/features/operator/operator-event/OperatorEvent.module.scss @@ -22,17 +22,39 @@ background-color: $gray-1250; } + &.grouped { + position: relative; + padding-left: 0.35rem; + background: + linear-gradient(90deg, color-mix(in srgb, transparent 88%, var(--group-colour, $gray-500) 12%), transparent 8rem), + $viewer-card-bg-color; + } + &.running { border-top: 1px solid $gray-1300; background-color: var(--operator-running-bg-override, $active-green); } + &.grouped.running { + background: + linear-gradient(90deg, color-mix(in srgb, transparent 82%, var(--group-colour, $gray-500) 18%), transparent 8rem), + var(--operator-running-bg-override, $active-green); + } + &.past { border-top: 1px solid transparent; opacity: 0.2; } } +.groupRail { + position: absolute; + inset-block: 0; + left: 0; + width: 0.35rem; + background-color: var(--group-colour, $gray-500); +} + .binder { grid-area: binder; color: $section-white; diff --git a/apps/client/src/features/operator/operator-event/OperatorEvent.tsx b/apps/client/src/features/operator/operator-event/OperatorEvent.tsx index a081bd04a..fea7068b6 100644 --- a/apps/client/src/features/operator/operator-event/OperatorEvent.tsx +++ b/apps/client/src/features/operator/operator-event/OperatorEvent.tsx @@ -25,6 +25,7 @@ interface OperatorEventProps { isLinkedToLoaded: boolean; isSelected: boolean; isPast: boolean; + groupColour?: string; selectedRef?: RefObject; showStart: boolean; subscribed: Subscribed; @@ -46,6 +47,7 @@ function OperatorEvent({ isLinkedToLoaded, isSelected, isPast, + groupColour, selectedRef, showStart, subscribed, @@ -68,7 +70,12 @@ function OperatorEvent({ const mouseHandlers = useLongPress(handleLongPress); const cueColours = colour && getAccessibleColour(colour); - const operatorClasses = cx([style.event, isSelected && style.running, isPast && style.past]); + const operatorClasses = cx([ + style.event, + groupColour && style.grouped, + isSelected && style.running, + isPast && style.past, + ]); const hasFields = subscribed.some((field) => field.value); const columnCount = subscribed.length ? Math.min(subscribed.length, 4) : 0; @@ -85,8 +92,10 @@ function OperatorEvent({ data-testid={cue} ref={selectedRef} onContextMenu={handleLongPress} + style={groupColour ? ({ '--group-colour': groupColour } as CSSProperties) : undefined} {...mouseHandlers} > + {groupColour &&
}
{cue}
diff --git a/apps/client/src/features/operator/operator-group/OperatorGroup.module.scss b/apps/client/src/features/operator/operator-group/OperatorGroup.module.scss index 44e29ab04..0f93f425e 100644 --- a/apps/client/src/features/operator/operator-group/OperatorGroup.module.scss +++ b/apps/client/src/features/operator/operator-group/OperatorGroup.module.scss @@ -1,13 +1,33 @@ .group { width: 100%; - padding: 0.25rem 0.5rem; + min-height: 2.5rem; + padding: 0.4rem 0.75rem; + border-left: 0.35rem solid var(--group-colour, $gray-500); background-color: $gray-1350; + background: color-mix(in srgb, transparent 88%, var(--group-colour, $gray-500) 12%); font-size: 1.25rem; + font-weight: 600; + + display: flex; + align-items: center; + gap: 1rem; + letter-spacing: 0; } -// tablet -@media (min-width: $min-tablet) { - .group { - padding: 0.25rem 1rem; - } +.title { + flex: 1 1 auto; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.meta { + display: flex; + flex: 0 0 auto; + align-items: center; + gap: 0.5rem; + color: rgba($ui-white, 0.55); + font-size: 0.875rem; + font-weight: 500; } diff --git a/apps/client/src/features/operator/operator-group/OperatorGroup.tsx b/apps/client/src/features/operator/operator-group/OperatorGroup.tsx index a30f9646e..eb8036c2f 100644 --- a/apps/client/src/features/operator/operator-group/OperatorGroup.tsx +++ b/apps/client/src/features/operator/operator-group/OperatorGroup.tsx @@ -1,12 +1,29 @@ -import { memo } from 'react'; +import { CSSProperties, memo } from 'react'; + +import { getAccessibleColour } from '../../../common/utils/styleUtils'; +import { formatDuration } from '../../../common/utils/time'; import style from './OperatorGroup.module.scss'; interface OperatorGroup { title: string; + colour: string; + count: number; + duration: number; } export default memo(OperatorGroup); -function OperatorGroup({ title }: OperatorGroup) { - return
{title}
; +function OperatorGroup({ title, colour, count, duration }: OperatorGroup) { + const groupColour = colour || '#929292'; + const groupColours = getAccessibleColour(groupColour); + + return ( +
+ {title} + + {`${count} ${count === 1 ? 'event' : 'events'}`} + {formatDuration(duration)} + +
+ ); }