From f208f148b763f897c278f7b48c0b499f6ca41c87 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Wed, 26 Aug 2026 12:33:32 +0000 Subject: [PATCH] refactor(ui): move the timer status icons off the stage preview The icon rail was absolutely positioned over the same box as the preview content, so at narrow widths it collided with the render - and now that the preview shows a real timer, it also sat under the blackout overlay. It moves into the options column as a compact row, where it reads as editor chrome rather than part of the stage. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_011CHxSQ6nWHuyar8feieRra --- apps/client/src/common/hooks/useSocket.ts | 2 +- .../control/message/TimerPreview.module.scss | 17 ------ .../features/control/message/TimerPreview.tsx | 49 ---------------- .../control/message/TimerStatus.module.scss | 12 ++++ .../features/control/message/TimerStatus.tsx | 58 +++++++++++++++++++ .../control/message/TimerViewControl.tsx | 3 + 6 files changed, 74 insertions(+), 67 deletions(-) create mode 100644 apps/client/src/features/control/message/TimerStatus.module.scss create mode 100644 apps/client/src/features/control/message/TimerStatus.tsx diff --git a/apps/client/src/common/hooks/useSocket.ts b/apps/client/src/common/hooks/useSocket.ts index 5009b612e..49e16de1c 100644 --- a/apps/client/src/common/hooks/useSocket.ts +++ b/apps/client/src/common/hooks/useSocket.ts @@ -38,7 +38,7 @@ export const useExternalMessageInput = createSelector((state: RuntimeStore) => ( visible: state.message.timer.secondarySource === 'secondary', })); -export const useMessagePreview = createSelector((state: RuntimeStore) => ({ +export const useTimerStatus = createSelector((state: RuntimeStore) => ({ timerType: state.eventNow?.timerType ?? null, countToEnd: state.eventNow?.countToEnd ?? false, })); diff --git a/apps/client/src/features/control/message/TimerPreview.module.scss b/apps/client/src/features/control/message/TimerPreview.module.scss index 02ae9635b..0968fed14 100644 --- a/apps/client/src/features/control/message/TimerPreview.module.scss +++ b/apps/client/src/features/control/message/TimerPreview.module.scss @@ -29,20 +29,3 @@ pointer-events: auto; } } - -.eventStatus { - position: absolute; - left: 0; - margin: 0.5rem 0.25rem; - display: flex; - flex-direction: column; - gap: 0.25rem; -} - -.statusIcon { - color: $gray-1000; - - &[data-active='true'] { - color: $active-indicator; - } -} diff --git a/apps/client/src/features/control/message/TimerPreview.tsx b/apps/client/src/features/control/message/TimerPreview.tsx index 9fcde5b13..6f62a8e7d 100644 --- a/apps/client/src/features/control/message/TimerPreview.tsx +++ b/apps/client/src/features/control/message/TimerPreview.tsx @@ -1,11 +1,5 @@ -import { TimerType } from 'ontime-types'; -import { IoArrowDown, IoArrowUp, IoBan, IoTime } from 'react-icons/io5'; -import { LuArrowDownToLine } from 'react-icons/lu'; - import { CornerWithPip } from '../../../common/components/editor-utils/EditorUtils'; -import Tooltip from '../../../common/components/tooltip/Tooltip'; import useViewSettings from '../../../common/hooks-query/useViewSettings'; -import { useMessagePreview } from '../../../common/hooks/useSocket'; import { handleLinks } from '../../../common/utils/linkUtils'; import PipRoot from '../../../views/editor/pip-timer/PipRoot'; import { PipTimer } from '../../../views/editor/pip-timer/PipTimer'; @@ -13,7 +7,6 @@ import { PipTimer } from '../../../views/editor/pip-timer/PipTimer'; import style from './TimerPreview.module.scss'; export default function TimerPreview() { - const { countToEnd, timerType } = useMessagePreview(); const { data } = useViewSettings(); return ( @@ -24,48 +17,6 @@ export default function TimerPreview() { handleLinks('timer', event)} pipElement={} /> -
- } - className={style.statusIcon} - data-active={timerType === TimerType.CountDown} - > - - - } - className={style.statusIcon} - data-active={timerType === TimerType.CountUp} - > - - - } - className={style.statusIcon} - data-active={timerType === TimerType.Clock} - > - - - } - className={style.statusIcon} - data-active={timerType === TimerType.None} - > - - - } - className={style.statusIcon} - data-active={countToEnd} - > - - -
); } diff --git a/apps/client/src/features/control/message/TimerStatus.module.scss b/apps/client/src/features/control/message/TimerStatus.module.scss new file mode 100644 index 000000000..3446e7ef9 --- /dev/null +++ b/apps/client/src/features/control/message/TimerStatus.module.scss @@ -0,0 +1,12 @@ +.timerStatus { + display: flex; + gap: 0.25rem; +} + +.statusIcon { + color: $gray-1000; + + &[data-active='true'] { + color: $active-indicator; + } +} diff --git a/apps/client/src/features/control/message/TimerStatus.tsx b/apps/client/src/features/control/message/TimerStatus.tsx new file mode 100644 index 000000000..343016c30 --- /dev/null +++ b/apps/client/src/features/control/message/TimerStatus.tsx @@ -0,0 +1,58 @@ +import { TimerType } from 'ontime-types'; +import { IoArrowDown, IoArrowUp, IoBan, IoTime } from 'react-icons/io5'; +import { LuArrowDownToLine } from 'react-icons/lu'; + +import Tooltip from '../../../common/components/tooltip/Tooltip'; +import { useTimerStatus } from '../../../common/hooks/useSocket'; + +import style from './TimerStatus.module.scss'; + +/** Read only summary of how the loaded event drives the stage timer */ +export default function TimerStatus() { + const { countToEnd, timerType } = useTimerStatus(); + + return ( +
+ } + className={style.statusIcon} + data-active={timerType === TimerType.CountDown} + > + + + } + className={style.statusIcon} + data-active={timerType === TimerType.CountUp} + > + + + } + className={style.statusIcon} + data-active={timerType === TimerType.Clock} + > + + + } + className={style.statusIcon} + data-active={timerType === TimerType.None} + > + + + } + className={style.statusIcon} + data-active={countToEnd} + > + + +
+ ); +} diff --git a/apps/client/src/features/control/message/TimerViewControl.tsx b/apps/client/src/features/control/message/TimerViewControl.tsx index a561d47b4..63e663310 100644 --- a/apps/client/src/features/control/message/TimerViewControl.tsx +++ b/apps/client/src/features/control/message/TimerViewControl.tsx @@ -6,6 +6,7 @@ import * as Editor from '../../../common/components/editor-utils/EditorUtils'; import Select from '../../../common/components/select/Select'; import { setMessage, useTimerViewControl } from '../../../common/hooks/useSocket'; import TimerPreview from './TimerPreview'; +import TimerStatus from './TimerStatus'; import style from './TimerViewControl.module.scss'; @@ -16,6 +17,8 @@ export default function TimerControlsPreview() {
+ +