diff --git a/apps/client/src/common/hooks/useSocket.ts b/apps/client/src/common/hooks/useSocket.ts index 49e16de1c..da94bb454 100644 --- a/apps/client/src/common/hooks/useSocket.ts +++ b/apps/client/src/common/hooks/useSocket.ts @@ -22,10 +22,14 @@ export const useRundownEditor = createSelector((state: RuntimeStore) => ({ nextEventId: state.eventNext?.id ?? null, })); -export const useTimerViewControl = createSelector((state: RuntimeStore) => ({ +export const useScreenControl = createSelector((state: RuntimeStore) => ({ blackout: state.message.timer.blackout, blink: state.message.timer.blink, - secondarySource: state.message.timer.secondarySource, + isScreenModified: + state.message.timer.visible || + state.message.timer.blink || + state.message.timer.blackout || + state.message.timer.secondarySource !== null, })); export const useTimerMessageInput = createSelector((state: RuntimeStore) => ({ @@ -33,9 +37,9 @@ export const useTimerMessageInput = createSelector((state: RuntimeStore) => ({ visible: state.message.timer.visible, })); -export const useExternalMessageInput = createSelector((state: RuntimeStore) => ({ +export const useSecondaryMessageInput = createSelector((state: RuntimeStore) => ({ text: state.message.secondary, - visible: state.message.timer.secondarySource === 'secondary', + source: state.message.timer.secondarySource, })); export const useTimerStatus = createSelector((state: RuntimeStore) => ({ diff --git a/apps/client/src/features/control/message/InputRow.module.scss b/apps/client/src/features/control/message/InputRow.module.scss index 877549f99..7730006a1 100644 --- a/apps/client/src/features/control/message/InputRow.module.scss +++ b/apps/client/src/features/control/message/InputRow.module.scss @@ -2,14 +2,12 @@ display: grid; grid-template-columns: 1fr auto; gap: $element-spacing; - margin-top: $element-inner-spacing; -} -.label { - font-size: $inner-section-text-size; - color: $label-gray; - - &.active { - color: $action-text-color; + &.withSource { + grid-template-columns: auto 1fr auto; } } + +.label.active { + color: $action-text-color; +} diff --git a/apps/client/src/features/control/message/InputRow.tsx b/apps/client/src/features/control/message/InputRow.tsx index c5559a5b9..59c5e8c37 100644 --- a/apps/client/src/features/control/message/InputRow.tsx +++ b/apps/client/src/features/control/message/InputRow.tsx @@ -1,5 +1,6 @@ -import { PropsWithChildren, useEffect, useRef, useState } from 'react'; +import { PropsWithChildren, ReactNode, useEffect, useRef, useState } from 'react'; +import * as Editor from '../../../common/components/editor-utils/EditorUtils'; import Input from '../../../common/components/input/input/Input'; import { cx } from '../../../common/utils/styleUtils'; @@ -9,12 +10,15 @@ interface InputRowProps { label: string; placeholder: string; text: string; + /** whether this text is currently on the audience screen */ visible: boolean; changeHandler: (newValue: string) => void; + /** control which picks where the text is shown, rendered before the input */ + sourcePicker?: ReactNode; } export default function InputRow(props: PropsWithChildren) { - const { label, placeholder, text, visible, changeHandler, children } = props; + const { label, placeholder, text, visible, changeHandler, sourcePicker, children } = props; const [value, setValue] = useState(text); const inputRef = useRef(null); @@ -43,10 +47,11 @@ export default function InputRow(props: PropsWithChildren) { return (
- -
+ +
+ {sourcePicker} {children}
diff --git a/apps/client/src/features/control/message/MessageControl.tsx b/apps/client/src/features/control/message/MessageControl.tsx index 54270651f..ecbab07a3 100644 --- a/apps/client/src/features/control/message/MessageControl.tsx +++ b/apps/client/src/features/control/message/MessageControl.tsx @@ -1,18 +1,18 @@ +import { SecondarySource } from 'ontime-types'; import { IoEye, IoEyeOffOutline } from 'react-icons/io5'; import IconButton from '../../../common/components/buttons/IconButton'; -import { - setMessage, - useExternalMessageInput as useSecondaryMessageInput, - useTimerMessageInput, -} from '../../../common/hooks/useSocket'; +import Select from '../../../common/components/select/Select'; +import { setMessage, useSecondaryMessageInput, useTimerMessageInput } from '../../../common/hooks/useSocket'; import InputRow from './InputRow'; -import TimerControlsPreview from './TimerViewControl'; +import ScreenControl from './ScreenControl'; +import TimerPreview from './TimerPreview'; export default function MessageControl() { return ( <> - + + @@ -24,7 +24,7 @@ function TimerMessageInput() { return ( setMessage.timerVisible(!visible)} variant={visible ? 'primary' : 'subtle'} > @@ -41,31 +42,46 @@ function TimerMessageInput() { ); } +/** + * The secondary line of the stage timer shows one of the aux timers or the secondary message. + * The select owns which one, the eye owns whether the line is shown at all. + */ function SecondaryInput() { - const { text, visible } = useSecondaryMessageInput(); - - const toggleSecondary = () => { - if (visible) { - setMessage.timerSecondarySource(null); - } else { - setMessage.timerSecondarySource('secondary'); - } - }; + const { text, source } = useSecondaryMessageInput(); + const isShowingSecondaryLine = source !== null; + const selectedSource = source ?? 'aux1'; return ( setMessage.secondaryMessage(newValue)} + sourcePicker={ + { - if (value === null) return; - // we can only update the remote if it is enabled - if (secondarySource !== null) { - setMessage.timerSecondarySource(value); - } - setValue(value); - }} - /> - - - ); -}