refactor: review timer styles

This commit is contained in:
Carlos Valente
2025-07-12 22:06:47 +02:00
committed by Carlos Valente
parent a69c5f354c
commit 7305edc398
13 changed files with 86 additions and 39 deletions
@@ -13,8 +13,13 @@ interface FitTextProps extends HTMLAttributes<HTMLDivElement> {
max?: number; // inclusive
}
export function FitText(props: PropsWithChildren<FitTextProps>) {
const { children, mode = 'multi', min = 16, max = 256, ...elementProps } = props;
export function FitText({
children,
mode = 'multi',
min = 16,
max = 256,
...elementProps
}: PropsWithChildren<FitTextProps>) {
const ref = useRef<HTMLDivElement>(null);
const isOverflown = useCallback(() => {
@@ -25,9 +25,8 @@
}
&:focus {
outline: none;
background-color: $gray-1300;
border: 2px solid $ui-white;
outline: 2px solid $blue-500;
background-color: $gray-1350;
}
&.current {
@@ -18,7 +18,9 @@ export default function PopoverContents({
<Popover.Positioner sideOffset={8} {...popoverProps}>
<Popover.Popup className={style.popup}>
{title && <Popover.Title className={style.title}>{title}</Popover.Title>}
<Popover.Description className={className}>{children}</Popover.Description>
<Popover.Description className={className} render={<div />}>
{children}
</Popover.Description>
</Popover.Popup>
</Popover.Positioner>
</Popover.Portal>
@@ -1,7 +1,7 @@
.inline {
display: flex;
align-items: center;
gap: 1rem;
gap: 0.5rem;
}
// attempt to match with ontimeTextInputs
@@ -43,8 +43,7 @@ export default function ParamInput({ paramField }: ParamInputProps) {
}
if (type === 'boolean') {
const defaultCheckedValue = isStringBoolean(searchParams.get(id)) || defaultValue;
return <Switch size='large' name={id} defaultChecked={defaultCheckedValue} />;
return <ControlledSwitch id={id} initialValue={isStringBoolean(searchParams.get(id)) || defaultValue} />;
}
if (type === 'number') {
@@ -123,3 +122,12 @@ function MultiOption({ paramField }: EditFormMultiOptionProps) {
</>
);
}
interface ControlledSwitchProps {
id: string;
initialValue: boolean;
}
function ControlledSwitch({ id, initialValue }: ControlledSwitchProps) {
const [checked, setChecked] = useState(initialValue);
return <Switch size='large' name={id} checked={checked} onCheckedChange={setChecked} />;
}
@@ -115,7 +115,7 @@ export default function Operator() {
const { process } = makeOperatorMetadata(selectedEventId);
return (
<div className={style.operatorContainer}>
<div className={style.operatorContainer} data-testid='operator-view'>
<ViewParamsEditor viewOptions={operatorOptions} />
{editEvent && <EditModal event={editEvent} onClose={() => setEditEvent(null)} />}
+12 -3
View File
@@ -35,9 +35,18 @@ interface BackstageProps {
settings: Settings | undefined;
}
export default function Backstage(props: BackstageProps) {
const { events, customFields, eventNext, eventNow, general, time, isMirrored, runtime, selectedId, settings } = props;
export default function Backstage({
events,
customFields,
eventNext,
eventNow,
general,
time,
isMirrored,
runtime,
selectedId,
settings,
}: BackstageProps) {
const { getLocalizedString } = useTranslation();
const { secondarySource } = useBackstageOptions();
const [blinkClass, setBlinkClass] = useState(false);
@@ -38,7 +38,12 @@ export default function StudioTimers({
const formattedSecondaryMessage = secondaryMessage || '-';
// gather presentation styles
const timerColour = getTimerColour(viewSettings, time.phase === TimerPhase.Warning, time.phase === TimerPhase.Danger);
const timerColour = getTimerColour(
viewSettings,
undefined,
time.phase === TimerPhase.Warning,
time.phase === TimerPhase.Danger,
);
return (
<div className='studio__timers'>
+4 -4
View File
@@ -101,7 +101,7 @@
.timer {
opacity: 1;
font-family: var(--timer-font, var(--font-family-override, $viewer-font-family));
color: var(--timer-colour, var(--timer-color-override, var(--phase-color)));
color: var(--timer-colour, var(--timer-color-override, $ui-white));
line-height: 0.9em;
text-align: center;
letter-spacing: 0.05em;
@@ -117,14 +117,14 @@
// use a class instead of a phase, to allow suppressing overtime style
&--finished {
color: var(--timer-overtime-color-override, $timer-finished-color);
color: var(--timer-colour, var(--timer-overtime-color-override, $timer-finished-color));
}
&[data-phase="warning"] {
color: var(--timer-warning-color-override, var(--phase-color));
color: var(--timer-colour, var(--timer-warning-color-override));
}
&[data-phase="danger"] {
color: var(--timer-danger-color-override, var(--phase-color));
color: var(--timer-colour, var(--timer-danger-color-override));
}
}
}
+5 -8
View File
@@ -68,7 +68,7 @@ export default function Timer({
timerType,
freezeOvertime,
freezeMessage,
hideOvertime,
hidePhase,
font,
keyColour,
textColour,
@@ -88,7 +88,7 @@ export default function Timer({
time.phase,
freezeOvertime,
freezeMessage,
hideOvertime,
hidePhase,
);
const isPlaying = getIsPlaying(time.playback);
const showClock = !hideClock && getShowClock(viewTimerType);
@@ -136,11 +136,11 @@ export default function Timer({
);
// gather presentation styles
const timerColour = getTimerColour(viewSettings, showWarning, showDanger);
const timerColour = getTimerColour(viewSettings, textColour, showWarning, showDanger);
const { timerFontSize, externalFontSize } = getEstimatedFontSize(display, secondaryContent);
const userStyles = {
...(keyColour && { '--timer-bg': keyColour }),
...(textColour && { '--timer-colour': textColour }),
...(textColour && { '--timer-colour': timerColour }),
...(font && { '--timer-font': font }),
};
@@ -183,10 +183,7 @@ export default function Timer({
) : (
<div
className={cx(['timer', !isPlaying && 'timer--paused', showFinished && 'timer--finished'])}
style={{
fontSize: `${timerFontSize}vw`,
'--phase-color': timerColour,
}}
style={{ fontSize: `${timerFontSize}vw` }}
data-phase={time.phase}
>
{display}
+5 -5
View File
@@ -65,9 +65,9 @@ export const getTimerOptions = (timeFormat: string, customFields: CustomFields):
placeholder: 'e.g. Time is up!',
},
{
id: 'hideOvertime',
title: 'Hide Overtime',
description: 'Whether to suppress overtime styles (red borders and red text)',
id: 'hidePhase',
title: 'Hide progress styles',
description: 'Whether to suppress the progress styles (warning, danger and overtime)',
type: 'boolean',
defaultValue: false,
},
@@ -187,7 +187,7 @@ type TimerOptions = {
timerType?: TimerType;
freezeOvertime: boolean;
freezeMessage: string;
hideOvertime: boolean;
hidePhase: boolean;
font?: string;
keyColour?: string;
textColour?: string;
@@ -217,7 +217,7 @@ function getOptionsFromParams(searchParams: URLSearchParams): TimerOptions {
timerType: timerType === TimerType.None ? undefined : timerType,
freezeOvertime: isStringBoolean(searchParams.get('freezeOvertime')),
freezeMessage: searchParams.get('freezeMessage') ?? '',
hideOvertime: isStringBoolean(searchParams.get('hideOvertime')),
hidePhase: isStringBoolean(searchParams.get('hidePhase')),
font: searchParams.get('font') ?? undefined,
keyColour: makeColourString(searchParams.get('keyColour')),
+23 -6
View File
@@ -83,15 +83,32 @@ export function getShowModifiers(
phase: TimerPhase,
freezeOvertime: boolean,
freezeMessage: string,
hideOvertime: boolean,
hidePhase: boolean,
) {
if (hidePhase) {
return {
showEndMessage: false,
showFinished: false,
showWarning: false,
showDanger: false,
};
}
const showModifiers = timerType === TimerType.CountDown || countToEnd;
const finished = phase === TimerPhase.Overtime;
if (!showModifiers) {
return {
showEndMessage: false,
showFinished: false,
showWarning: false,
showDanger: false,
};
}
return {
showEndMessage: showModifiers && finished && freezeOvertime && freezeMessage !== '',
showFinished: showModifiers && !hideOvertime && finished,
showWarning: showModifiers && phase === TimerPhase.Warning,
showDanger: showModifiers && phase === TimerPhase.Danger,
showEndMessage: freezeOvertime && freezeMessage !== '',
showFinished: phase === TimerPhase.Overtime,
showWarning: phase === TimerPhase.Warning,
showDanger: phase === TimerPhase.Danger,
};
}
@@ -3,8 +3,13 @@ import { ViewSettings } from 'ontime-types';
/**
* Which colour should the timer have at a given moment
*/
export function getTimerColour(viewSettings: ViewSettings, showWarning: boolean, showDanger: boolean) {
export function getTimerColour(
viewSettings: ViewSettings,
timerColour: string | undefined,
showWarning: boolean,
showDanger: boolean,
) {
if (showWarning) return viewSettings.warningColor;
if (showDanger) return viewSettings.dangerColor;
return viewSettings.normalColor;
return timerColour || viewSettings.normalColor;
}