Skip to content

Commit c053313

Browse files
committed
wip: rundownheader hover and re-design
1 parent d4b363f commit c053313

File tree

4 files changed

+216
-5
lines changed

4 files changed

+216
-5
lines changed

packages/webui/src/client/styles/rundownView.scss

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ body.no-overflow {
267267
}
268268

269269
.menu-icon-button {
270+
margin-top: 10px;
270271
background: none;
271272
border: none;
272273
cursor: pointer;
@@ -288,7 +289,8 @@ body.no-overflow {
288289
}
289290

290291
.timing {
291-
margin: 0 0;
292+
margin-top: 10px;
293+
margin-left: 0px;
292294
min-width: auto;
293295
width: 100%;
294296
text-align: center;
@@ -414,6 +416,12 @@ body.no-overflow {
414416
text-align: right;
415417
}
416418

419+
&.center {
420+
left: 50%;
421+
transform: translateX(-50%);
422+
text-align: center;
423+
}
424+
417425
&.hide-overflow {
418426
overflow: hidden;
419427
text-overflow: ellipsis;
@@ -437,6 +445,11 @@ body.no-overflow {
437445
}
438446
}
439447

448+
.planned-end-time {
449+
color: #ffffff;
450+
font-style: italic;
451+
}
452+
440453
&.heavy-light {
441454
font-weight: 600;
442455

packages/webui/src/client/ui/RundownView/RundownHeader/TimingDisplay.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import * as RundownResolver from '../../../lib/RundownResolver'
77
import { AutoNextStatus } from '../RundownTiming/AutoNextStatus'
88
import { CurrentPartOrSegmentRemaining } from '../RundownTiming/CurrentPartOrSegmentRemaining'
99
import { NextBreakTiming } from '../RundownTiming/NextBreakTiming'
10-
import { PlaylistEndTiming } from '../RundownTiming/PlaylistEndTiming'
11-
import { PlaylistStartTiming } from '../RundownTiming/PlaylistStartTiming'
10+
import { PlaylistEndTimingV2 } from '../RundownTiming/PlaylistEndTimingV2'
11+
import { PlaylistStartTimingV2 } from '../RundownTiming/PlaylistStartTimingV2'
1212
import { useTiming } from '../RundownTiming/withTiming'
1313

1414
interface ITimingDisplayProps {
@@ -56,7 +56,7 @@ export function TimingDisplay({ rundownPlaylist, layout, isHovered }: ITimingDis
5656
</div>
5757
<div className="timing__counters">
5858
<div className="timing__counters__center">
59-
<PlaylistStartTiming rundownPlaylist={rundownPlaylist} hidePlannedStart={false} hideDiff={true} />
59+
<PlaylistStartTimingV2 rundownPlaylist={rundownPlaylist} hidePlannedStart={false} hideDiff={true} />
6060
{showNextBreakTiming ? (
6161
<NextBreakTiming
6262
rundownsBeforeBreak={timingDurations.rundownsBeforeNextBreak!}
@@ -65,7 +65,7 @@ export function TimingDisplay({ rundownPlaylist, layout, isHovered }: ITimingDis
6565
/>
6666
) : null}
6767
{showEndTiming ? (
68-
<PlaylistEndTiming
68+
<PlaylistEndTimingV2
6969
rundownPlaylist={rundownPlaylist}
7070
loop={RundownResolver.isLoopRunning(rundownPlaylist)}
7171
expectedStart={expectedStart}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import React from 'react'
2+
import { useTranslation } from 'react-i18next'
3+
import Moment from 'react-moment'
4+
import { getCurrentTime } from '../../../lib/systemTime.js'
5+
import { RundownUtils } from '../../../lib/rundown.js'
6+
import { useTiming } from './withTiming.js'
7+
import ClassNames from 'classnames'
8+
import { DBRundownPlaylist } from '@sofie-automation/corelib/dist/dataModel/RundownPlaylist'
9+
import { getPlaylistTimingDiff } from '../../../lib/rundownTiming.js'
10+
import { isLoopRunning } from '../../../lib/RundownResolver.js'
11+
12+
interface IEndTimingProps {
13+
rundownPlaylist: DBRundownPlaylist
14+
loop?: boolean
15+
expectedStart?: number
16+
expectedDuration?: number
17+
expectedEnd?: number
18+
endLabel?: string
19+
hidePlannedEndLabel?: boolean
20+
hideDiffLabel?: boolean
21+
hidePlannedEnd?: boolean
22+
hideCountdown?: boolean
23+
hideDiff?: boolean
24+
}
25+
26+
export function PlaylistEndTimingV2({
27+
rundownPlaylist,
28+
loop,
29+
expectedStart,
30+
expectedDuration,
31+
expectedEnd,
32+
endLabel,
33+
hidePlannedEndLabel,
34+
hideDiffLabel,
35+
hidePlannedEnd,
36+
hideCountdown,
37+
hideDiff,
38+
}: IEndTimingProps): JSX.Element {
39+
const { t } = useTranslation()
40+
41+
const timingDurations = useTiming()
42+
43+
const overUnderClock = getPlaylistTimingDiff(rundownPlaylist, timingDurations) ?? 0
44+
const now = timingDurations.currentTime ?? getCurrentTime()
45+
46+
return (
47+
<React.Fragment>
48+
{!hideDiff ? (
49+
timingDurations ? (
50+
<span
51+
className={ClassNames('timing-clock heavy-light ', {
52+
heavy: overUnderClock < 0,
53+
light: overUnderClock >= 0,
54+
})}
55+
role="timer"
56+
>
57+
{!hideDiffLabel && (
58+
<span className="timing-clock-label center">{overUnderClock < 0 ? t('Under') : t('Over')}</span>
59+
)}
60+
{RundownUtils.formatDiffToTimecode(overUnderClock, true, false, true, true, true, undefined, true, true)}
61+
</span>
62+
) : null
63+
) : null}
64+
65+
{!loop &&
66+
!hideCountdown &&
67+
(expectedEnd ? (
68+
<span className="timing-clock countdown plan-end" role="timer">
69+
{RundownUtils.formatDiffToTimecode(now - expectedEnd, true, true, true)}
70+
</span>
71+
) : expectedStart && expectedDuration ? (
72+
<span className="timing-clock countdown plan-end" role="timer">
73+
{RundownUtils.formatDiffToTimecode(getCurrentTime() - (expectedStart + expectedDuration), true, true, true)}
74+
</span>
75+
) : null)}
76+
77+
{!hidePlannedEnd ? (
78+
expectedEnd ? (
79+
!rundownPlaylist.startedPlayback ? (
80+
<span className="timing-clock plan-end visual-last-child" role="timer">
81+
{!hidePlannedEndLabel && <span className="timing-clock-label right">{endLabel ?? t('Planned End')}</span>}
82+
<Moment interval={0} format="HH:mm:ss" date={expectedEnd} />
83+
</span>
84+
) : (
85+
<span className="timing-clock plan-end visual-last-child" role="timer">
86+
{!hidePlannedEndLabel && (
87+
<span className="timing-clock-label right">{endLabel ?? t('Expected End')}</span>
88+
)}
89+
<Moment interval={0} format="HH:mm:ss" date={expectedEnd} />
90+
</span>
91+
)
92+
) : timingDurations ? (
93+
isLoopRunning(rundownPlaylist) ? (
94+
timingDurations.partCountdown && rundownPlaylist.activationId && rundownPlaylist.currentPartInfo ? (
95+
<span className="timing-clock plan-end visual-last-child" role="timer">
96+
{!hidePlannedEndLabel && <span className="timing-clock-label right">{t('Next Loop at')}</span>}
97+
<Moment
98+
interval={0}
99+
format="HH:mm:ss"
100+
date={now + (timingDurations.partCountdown[Object.keys(timingDurations.partCountdown)[0]] || 0)}
101+
/>
102+
</span>
103+
) : null
104+
) : (
105+
<span className="timing-clock plan-end visual-last-child" role="timer">
106+
{!hidePlannedEndLabel && (
107+
<span className="timing-clock-label right">{endLabel ?? t('Planned End At')}</span>
108+
)}
109+
<span className="planned-end-time">
110+
<Moment
111+
interval={0}
112+
format="HH:mm:ss"
113+
date={(expectedStart || now) + (timingDurations.remainingPlaylistDuration || 0)}
114+
/>
115+
</span>
116+
</span>
117+
)
118+
) : null
119+
) : null}
120+
</React.Fragment>
121+
)
122+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import React from 'react'
2+
import { useTranslation } from 'react-i18next'
3+
import Moment from 'react-moment'
4+
import { DBRundownPlaylist } from '@sofie-automation/corelib/dist/dataModel/RundownPlaylist'
5+
import { RundownUtils } from '../../../lib/rundown.js'
6+
import { getCurrentTime } from '../../../lib/systemTime.js'
7+
import ClassNames from 'classnames'
8+
import { PlaylistTiming } from '@sofie-automation/corelib/dist/playout/rundownTiming'
9+
10+
interface IStartTimingProps {
11+
rundownPlaylist: DBRundownPlaylist
12+
hidePlannedStart?: boolean
13+
hideDiff?: boolean
14+
plannedStartText?: string
15+
}
16+
17+
export function PlaylistStartTimingV2({
18+
rundownPlaylist,
19+
hidePlannedStart,
20+
hideDiff,
21+
plannedStartText,
22+
}: IStartTimingProps): JSX.Element {
23+
const { t } = useTranslation()
24+
25+
const playlistExpectedStart = PlaylistTiming.getExpectedStart(rundownPlaylist.timing)
26+
const playlistExpectedEnd = PlaylistTiming.getExpectedEnd(rundownPlaylist.timing)
27+
const playlistExpectedDuration = PlaylistTiming.getExpectedDuration(rundownPlaylist.timing)
28+
const expectedStart = playlistExpectedStart
29+
? playlistExpectedStart
30+
: playlistExpectedDuration && playlistExpectedEnd
31+
? playlistExpectedEnd - playlistExpectedDuration
32+
: undefined
33+
34+
return (
35+
<React.Fragment>
36+
{!hidePlannedStart &&
37+
(rundownPlaylist.startedPlayback && rundownPlaylist.activationId && !rundownPlaylist.rehearsal ? (
38+
<span className="timing-clock plan-start left" role="timer">
39+
<span className="timing-clock-label left">{t('Started')}</span>
40+
<Moment interval={0} format="HH:mm:ss" date={rundownPlaylist.startedPlayback} />
41+
</span>
42+
) : playlistExpectedStart ? (
43+
<span className="timing-clock plan-start left" role="timer">
44+
<span className="timing-clock-label left">{plannedStartText || t('Planned Start')}</span>
45+
<Moment interval={0} format="HH:mm:ss" date={playlistExpectedStart} />
46+
</span>
47+
) : playlistExpectedEnd && playlistExpectedDuration ? (
48+
<span className="timing-clock plan-start left" role="timer">
49+
<span className="timing-clock-label left">{plannedStartText || t('Expected Start')}</span>
50+
<Moment interval={0} format="HH:mm:ss" date={playlistExpectedEnd - playlistExpectedDuration} />
51+
</span>
52+
) : null)}
53+
{!hideDiff && expectedStart && (
54+
<span
55+
className={ClassNames('timing-clock heavy-light left', {
56+
heavy: getCurrentTime() > expectedStart,
57+
light: getCurrentTime() <= expectedStart,
58+
})}
59+
role="timer"
60+
>
61+
<span className="timing-clock-label">{t('Diff')}</span>
62+
{rundownPlaylist.startedPlayback
63+
? RundownUtils.formatDiffToTimecode(
64+
rundownPlaylist.startedPlayback - expectedStart,
65+
true,
66+
false,
67+
true,
68+
true,
69+
true
70+
)
71+
: RundownUtils.formatDiffToTimecode(getCurrentTime() - expectedStart, true, false, true, true, true)}
72+
</span>
73+
)}
74+
</React.Fragment>
75+
)
76+
}

0 commit comments

Comments
 (0)