diff --git a/apps/client/src/common/models/ViewSettings.type.ts b/apps/client/src/common/models/ViewSettings.type.ts index 4bcca29c3..ecefd9a16 100644 --- a/apps/client/src/common/models/ViewSettings.type.ts +++ b/apps/client/src/common/models/ViewSettings.type.ts @@ -1,8 +1,8 @@ import { ViewSettings } from 'ontime-types'; export const viewsSettingsPlaceholder: ViewSettings = { - dangerColor: '#ED3333', + dangerColor: '#ff7300', normalColor: '#ffffffcc', overrideStyles: false, - warningColor: '#FFAB33', + warningColor: '#ffa528', }; diff --git a/apps/client/src/common/utils/offset.ts b/apps/client/src/common/utils/offset.ts new file mode 100644 index 000000000..37b08a32b --- /dev/null +++ b/apps/client/src/common/utils/offset.ts @@ -0,0 +1,25 @@ +import { MaybeNumber } from 'ontime-types'; +import { millisToString } from 'ontime-utils'; + +import { enDash } from './styleUtils'; + +/** + * Formats offset text + */ +export function getOffsetText(offset: MaybeNumber): string { + if (offset === null) { + return enDash; + } + + let offsetText = ''; + if (offset < 0) offsetText += '-'; + if (offset > 0) offsetText += '+'; + offsetText += millisToString(Math.abs(offset)); + return offsetText; +} + +export function getOffsetState(offset: MaybeNumber): 'ahead' | 'behind' | 'muted' | null { + if (offset === null) return null; + if (offset === 0) return 'muted'; + return offset < 0 ? 'behind' : 'ahead'; +} diff --git a/apps/client/src/features/control/message/TimerPreview.tsx b/apps/client/src/features/control/message/TimerPreview.tsx index 9178220af..9b9271d8e 100644 --- a/apps/client/src/features/control/message/TimerPreview.tsx +++ b/apps/client/src/features/control/message/TimerPreview.tsx @@ -42,8 +42,8 @@ export default function TimerPreview() { const overrideColour = (() => { // override fallback colours from starter project - if (phase === TimerPhase.Warning) return data.warningColor ?? '#FFAB33'; - if (phase === TimerPhase.Danger) return data.dangerColor ?? '#ED3333'; + if (phase === TimerPhase.Warning) return data.warningColor ?? '#ffa528'; + if (phase === TimerPhase.Danger) return data.dangerColor ?? '#ff7300'; return data.normalColor ?? '#FFFC'; })(); diff --git a/apps/client/src/features/overview/CuesheetOverview.tsx b/apps/client/src/features/overview/CuesheetOverview.tsx index 9dfe53771..dca456e39 100644 --- a/apps/client/src/features/overview/CuesheetOverview.tsx +++ b/apps/client/src/features/overview/CuesheetOverview.tsx @@ -2,7 +2,7 @@ import { memo, PropsWithChildren } from 'react'; import { useIsMobileScreen } from '../../common/hooks/useIsMobileScreen'; -import { ClockOverview, MetadataTimes, RuntimeOverview, StartTimes, TimerOverview } from './composite/TimeElements'; +import { ClockOverview, MetadataTimes, OffsetOverview, StartTimes, TimerOverview } from './composite/TimeElements'; import TitleOverview from './composite/TitleOverview'; import { OverviewWrapper } from './OverviewWrapper'; @@ -18,7 +18,7 @@ function CuesheetMobile({ children }: PropsWithChildren) { return ( - + ); } @@ -29,7 +29,7 @@ function CuesheetDesktop({ children }: PropsWithChildren) { - + diff --git a/apps/client/src/features/overview/EditorOverview.tsx b/apps/client/src/features/overview/EditorOverview.tsx index 2a0286121..b3ab5c9ce 100644 --- a/apps/client/src/features/overview/EditorOverview.tsx +++ b/apps/client/src/features/overview/EditorOverview.tsx @@ -1,6 +1,6 @@ import { memo, PropsWithChildren } from 'react'; -import { ClockOverview, MetadataTimes, ProgressOverview, RuntimeOverview, StartTimes } from './composite/TimeElements'; +import { ClockOverview, MetadataTimes, OffsetOverview, ProgressOverview, StartTimes } from './composite/TimeElements'; import TitleOverview from './composite/TitleOverview'; import { OverviewWrapper } from './OverviewWrapper'; @@ -11,7 +11,7 @@ function EditorOverview({ children }: PropsWithChildren) { - + diff --git a/apps/client/src/features/overview/composite/TimeElements.tsx b/apps/client/src/features/overview/composite/TimeElements.tsx index c62b4e704..c11716610 100644 --- a/apps/client/src/features/overview/composite/TimeElements.tsx +++ b/apps/client/src/features/overview/composite/TimeElements.tsx @@ -13,9 +13,10 @@ import { useTimer, } from '../../../common/hooks/useSocket'; import { useEntry } from '../../../common/hooks-query/useRundown'; +import { getOffsetState, getOffsetText } from '../../../common/utils/offset'; import { cx, enDash, timerPlaceholder } from '../../../common/utils/styleUtils'; import { formatTime, useTimeUntilStart } from '../../../common/utils/time'; -import { calculateEndAndDaySpan, formattedTime, getOffsetText } from '../overview.utils'; +import { calculateEndAndDaySpan, formattedTime } from '../overview.utils'; import { TimeColumn } from './TimeLayout'; @@ -193,14 +194,16 @@ export function ProgressOverview() { return ; } -export function RuntimeOverview() { +export function OffsetOverview() { const { offset, playback } = useRuntimePlaybackOverview(); const isPlaying = isPlaybackActive(playback); - const offsetText = getOffsetText(isPlaying ? offset : null); - const offsetClasses = cx([style.offset, isPlaying && (offset < 0 ? style.behind : style.ahead)]); + const correctedOffset = offset * -1; + const offsetState = getOffsetState(correctedOffset); + const offsetClasses = cx([style.offset, offsetState && style[offsetState]]); + const offsetText = getOffsetText(isPlaying ? correctedOffset : null); - return ; + return ; } export function ClockOverview() { diff --git a/apps/client/src/features/overview/overview.utils.ts b/apps/client/src/features/overview/overview.utils.ts index f5e175349..61eeac978 100644 --- a/apps/client/src/features/overview/overview.utils.ts +++ b/apps/client/src/features/overview/overview.utils.ts @@ -1,7 +1,7 @@ import { MaybeNumber, TimerType } from 'ontime-types'; import { dayInMs, millisToString } from 'ontime-utils'; -import { enDash, timerPlaceholder, timerPlaceholderMin } from '../../common/utils/styleUtils'; +import { timerPlaceholder, timerPlaceholderMin } from '../../common/utils/styleUtils'; /** * Encapsulates the logic for formatting time in overview @@ -24,15 +24,3 @@ export function calculateEndAndDaySpan(end: MaybeNumber): [MaybeNumber, number] return [end, 0]; } - -/** - * Formats offset text - * @param offset - * @returns - */ -export function getOffsetText(offset: MaybeNumber): string { - if (offset === null) { - return enDash; - } - return millisToString(offset, { fallback: enDash }); -} diff --git a/apps/client/src/features/rundown/entry-editor/BlockEditor.tsx b/apps/client/src/features/rundown/entry-editor/BlockEditor.tsx index 930f59c13..fb1811c3f 100644 --- a/apps/client/src/features/rundown/entry-editor/BlockEditor.tsx +++ b/apps/client/src/features/rundown/entry-editor/BlockEditor.tsx @@ -53,7 +53,8 @@ export default function BlockEditor({ block }: BlockEditorProps) { ); const isEditor = window.location.pathname.includes('editor'); - const planOffset = typeof block.targetDuration !== 'number' ? null : block.targetDuration - block.duration; + const planOffset = typeof block.targetDuration !== 'number' ? null : block.duration - block.targetDuration; + const planOffsetLabel = planOffset !== null && planOffset > 0 ? 'behind' : 'ahead'; return (
@@ -94,11 +95,8 @@ export default function BlockEditor({ block }: BlockEditorProps) {
Plan offset - { - // TODO: update remote data - // TODO: remove tab index - } - + + {planOffset !== null && planOffset > 0 ? '+' : ''} {millisToString(planOffset, { fallback: enDash })}
diff --git a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/DurationInput.tsx b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/DurationInput.tsx index 1d9d63a46..bb251de28 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/DurationInput.tsx +++ b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/DurationInput.tsx @@ -103,7 +103,7 @@ function DurationInput({ onClick={handleFakeFocus} onFocus={handleFakeFocus} muted={!lockedValue} - delayed={delayed} + offset={delayed ? 'behind' : undefined} ref={textRef} > {children} diff --git a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TextLikeInput.module.scss b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TextLikeInput.module.scss index cdba636fc..9a43cb6a7 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TextLikeInput.module.scss +++ b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TextLikeInput.module.scss @@ -14,7 +14,11 @@ overflow: hidden; - &.delayed { + &.ahead { + color: $playback-ahead; + } + + &.behind { color: $ontime-delay-text; } diff --git a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TextLikeInput.tsx b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TextLikeInput.tsx index ee0415756..d8bbe4910 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TextLikeInput.tsx +++ b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TextLikeInput.tsx @@ -5,29 +5,30 @@ import { cx } from '../../../../common/utils/styleUtils'; import style from './TextLikeInput.module.scss'; interface TextLikeInputProps extends HTMLAttributes { - delayed?: boolean; + offset?: 'ahead' | 'behind'; muted?: boolean; } -const TextLikeInput = forwardRef((props: PropsWithChildren, textRef) => { - const { delayed, muted, children, className, ...elementProps } = props; - const ref = useRef(null); - const classes = cx([style.textInput, delayed && style.delayed, muted && style.muted, className]); +const TextLikeInput = forwardRef( + ({ offset, muted, children, className, ...elementProps }: PropsWithChildren, textRef) => { + const ref = useRef(null); + const classes = cx([style.textInput, offset && style[offset], muted && style.muted, className]); - useImperativeHandle(textRef, () => { - return { - focusParentElement() { - ref.current?.parentElement?.focus(); - }, - }; - }); + useImperativeHandle(textRef, () => { + return { + focusParentElement() { + ref.current?.parentElement?.focus(); + }, + }; + }); - return ( -
- {children} -
- ); -}); + return ( +
+ {children} +
+ ); + }, +); TextLikeInput.displayName = 'TextLikeInput'; diff --git a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TimeInput.tsx b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TimeInput.tsx index f4c914da0..7e89967be 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TimeInput.tsx +++ b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TimeInput.tsx @@ -105,7 +105,7 @@ function TimeInputDuration({ onClick={handleFakeFocus} onFocus={handleFakeFocus} muted={!lockedValue} - delayed={delayed} + offset={delayed ? 'behind' : undefined} ref={textRef} > {children} diff --git a/apps/client/src/views/studio/StudioTimers.tsx b/apps/client/src/views/studio/StudioTimers.tsx index b2ff9cd94..7f25299b6 100644 --- a/apps/client/src/views/studio/StudioTimers.tsx +++ b/apps/client/src/views/studio/StudioTimers.tsx @@ -2,6 +2,7 @@ import { OntimeEvent, Playback, Runtime, TimerPhase, TimerState, ViewSettings } import { millisToString } from 'ontime-utils'; import { useAuxTimersTime } from '../../common/hooks/useSocket'; +import { getOffsetState } from '../../common/utils/offset'; import { cx } from '../../common/utils/styleUtils'; import { useTranslation } from '../../translation/TranslationProvider'; import { getTimerColour } from '../utils/presentation.utils'; @@ -45,6 +46,8 @@ export default function StudioTimers({ time.phase === TimerPhase.Danger, ); + const offsetState = getOffsetState(runtime.offset); + return (
@@ -54,15 +57,8 @@ export default function StudioTimers({
{schedule.actualStart}
-
Offset
-
+
Over / under
+
{schedule.offset}
diff --git a/apps/client/src/views/studio/studioTimers.utils.ts b/apps/client/src/views/studio/studioTimers.utils.ts index 76984891c..3baa511b0 100644 --- a/apps/client/src/views/studio/studioTimers.utils.ts +++ b/apps/client/src/views/studio/studioTimers.utils.ts @@ -1,14 +1,16 @@ import { OntimeEvent, Runtime, TimerState } from 'ontime-types'; import { millisToString } from 'ontime-utils'; +import { getOffsetText } from '../../common/utils/offset'; import { formatTime } from '../../common/utils/time'; const timeFormat = { format12: 'h:mm a', format24: 'HH:mm' }; export function getFormattedScheduleTimes(runtime: Runtime) { + const correctedOffset = runtime.offset !== null ? runtime.offset * -1 : null; return { actualStart: formatTime(runtime.actualStart, timeFormat), expectedEnd: formatTime(runtime.expectedEnd, timeFormat), - offset: millisToString(runtime.offset), + offset: getOffsetText(correctedOffset), }; } diff --git a/apps/server/src/models/dataModel.ts b/apps/server/src/models/dataModel.ts index 26f0cfb6d..47abd6668 100644 --- a/apps/server/src/models/dataModel.ts +++ b/apps/server/src/models/dataModel.ts @@ -33,8 +33,8 @@ export const dbModel: DatabaseModel = { viewSettings: { overrideStyles: false, normalColor: '#ffffffcc', - warningColor: '#FFAB33', - dangerColor: '#ED3333', + warningColor: '#ffa528', + dangerColor: '#ff7300', }, urlPresets: [], customFields: {}, diff --git a/apps/server/src/models/demoProject.ts b/apps/server/src/models/demoProject.ts index 84e85f67a..9798ae9f5 100644 --- a/apps/server/src/models/demoProject.ts +++ b/apps/server/src/models/demoProject.ts @@ -532,10 +532,10 @@ export const demoDb: DatabaseModel = { language: 'en', }, viewSettings: { - dangerColor: '#ED3333', + dangerColor: '#ff7300', normalColor: '#ffffffcc', overrideStyles: false, - warningColor: '#FFAB33', + warningColor: '#ffa528', }, customFields: { Song: { diff --git a/apps/server/test-db/db.json b/apps/server/test-db/db.json index 9dc56a557..ba99145cd 100644 --- a/apps/server/test-db/db.json +++ b/apps/server/test-db/db.json @@ -467,10 +467,10 @@ "language": "en" }, "viewSettings": { - "dangerColor": "#ED3333", + "dangerColor": "#ff7300", "normalColor": "#ffffffcc", "overrideStyles": false, - "warningColor": "#FFAB33" + "warningColor": "#ffa528" }, "customFields": { "song": { diff --git a/e2e/tests/fixtures/e2e-test-db.json b/e2e/tests/fixtures/e2e-test-db.json index 8cc730fcf..004934c52 100644 --- a/e2e/tests/fixtures/e2e-test-db.json +++ b/e2e/tests/fixtures/e2e-test-db.json @@ -484,10 +484,10 @@ "language": "en" }, "viewSettings": { - "dangerColor": "#ED3333", + "dangerColor": "#ff7300", "normalColor": "#ffffffcc", "overrideStyles": false, - "warningColor": "#FFAB33" + "warningColor": "#ffa528" }, "customFields": { "Song": {