mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-10 00:29:41 +00:00
refactor: add options to hide schedule
This commit is contained in:
committed by
Carlos Valente
parent
8bd7645c95
commit
7b932ef0f7
@@ -42,6 +42,11 @@ $orange-active: #f60;
|
|||||||
grid-template-areas: 'clock schedule';
|
grid-template-areas: 'clock schedule';
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
&.hide-right {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-areas: 'clock';
|
||||||
|
}
|
||||||
|
|
||||||
.clock-container {
|
.clock-container {
|
||||||
grid-area: clock;
|
grid-area: clock;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
import type { OntimeEvent, OntimeRundown, Settings, ViewSettings } from 'ontime-types';
|
import type { MaybeString, OntimeEvent, OntimeRundown, Settings, ViewSettings } from 'ontime-types';
|
||||||
import { isOntimeEvent, Playback } from 'ontime-types';
|
import { Playback } from 'ontime-types';
|
||||||
import { millisToString, removeSeconds } from 'ontime-utils';
|
import { millisToString, removeSeconds, secondsInMillis } from 'ontime-utils';
|
||||||
|
|
||||||
import { overrideStylesURL } from '../../../common/api/constants';
|
import { overrideStylesURL } from '../../../common/api/constants';
|
||||||
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
|
||||||
@@ -10,11 +10,10 @@ import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet
|
|||||||
import { useWindowTitle } from '../../../common/hooks/useWindowTitle';
|
import { useWindowTitle } from '../../../common/hooks/useWindowTitle';
|
||||||
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
|
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
|
||||||
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
|
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
|
||||||
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
|
|
||||||
import { isStringBoolean } from '../common/viewUtils';
|
import { isStringBoolean } from '../common/viewUtils';
|
||||||
|
|
||||||
import { getStudioClockOptions } from './studioClock.options';
|
import { getStudioClockOptions } from './studioClock.options';
|
||||||
import { secondsInMillis, trimRundown } from './studioClock.utils';
|
import StudioClockSchedule from './StudioClockSchedule';
|
||||||
|
|
||||||
import './StudioClock.scss';
|
import './StudioClock.scss';
|
||||||
|
|
||||||
@@ -23,8 +22,8 @@ interface StudioClockProps {
|
|||||||
eventNext: OntimeEvent | null;
|
eventNext: OntimeEvent | null;
|
||||||
time: ViewExtendedTimer;
|
time: ViewExtendedTimer;
|
||||||
backstageEvents: OntimeRundown;
|
backstageEvents: OntimeRundown;
|
||||||
selectedId: string | null;
|
selectedId: MaybeString;
|
||||||
nextId: string | null;
|
nextId: MaybeString;
|
||||||
onAir: boolean;
|
onAir: boolean;
|
||||||
viewSettings: ViewSettings;
|
viewSettings: ViewSettings;
|
||||||
settings: Settings | undefined;
|
settings: Settings | undefined;
|
||||||
@@ -38,16 +37,13 @@ export default function StudioClock(props: StudioClockProps) {
|
|||||||
useRuntimeStylesheet(viewSettings?.overrideStyles && overrideStylesURL);
|
useRuntimeStylesheet(viewSettings?.overrideStyles && overrideStylesURL);
|
||||||
const { fontSize: titleFontSize, ref: titleRef } = useFitText({ minFontSize: 150, maxFontSize: 500 });
|
const { fontSize: titleFontSize, ref: titleRef } = useFitText({ minFontSize: 150, maxFontSize: 500 });
|
||||||
|
|
||||||
const activeIndicators = [...Array(12).keys()];
|
|
||||||
const secondsIndicators = [...Array(60).keys()];
|
|
||||||
|
|
||||||
// TODO: fit titles on screen
|
|
||||||
const MAX_TITLES = 11;
|
|
||||||
|
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
|
|
||||||
useWindowTitle('Studio Clock');
|
useWindowTitle('Studio Clock');
|
||||||
|
|
||||||
|
const activeIndicators = [...Array(12).keys()];
|
||||||
|
const secondsIndicators = [...Array(60).keys()];
|
||||||
|
|
||||||
let clock = formatTime(time.clock);
|
let clock = formatTime(time.clock);
|
||||||
let hasAmPm = '';
|
let hasAmPm = '';
|
||||||
if (clock.includes('AM')) {
|
if (clock.includes('AM')) {
|
||||||
@@ -65,8 +61,7 @@ export default function StudioClock(props: StudioClockProps) {
|
|||||||
const defaultFormat = getDefaultFormat(settings?.timeFormat);
|
const defaultFormat = getDefaultFormat(settings?.timeFormat);
|
||||||
const studioClockOptions = getStudioClockOptions(defaultFormat);
|
const studioClockOptions = getStudioClockOptions(defaultFormat);
|
||||||
|
|
||||||
const delayed = backstageEvents.filter((event) => isOntimeEvent(event)) as OntimeEvent[];
|
const hideRight = isStringBoolean(searchParams.get('hideRight'));
|
||||||
const trimmedRundown = trimRundown(delayed, selectedId, MAX_TITLES);
|
|
||||||
let timer = millisToString(time.current, { fallback: '---' });
|
let timer = millisToString(time.current, { fallback: '---' });
|
||||||
const hideSeconds = isStringBoolean(searchParams.get('hideTimerSeconds'));
|
const hideSeconds = isStringBoolean(searchParams.get('hideTimerSeconds'));
|
||||||
if (time.current != null && hideSeconds) {
|
if (time.current != null && hideSeconds) {
|
||||||
@@ -74,7 +69,10 @@ export default function StudioClock(props: StudioClockProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`studio-clock ${isMirrored ? 'mirror' : ''}`} data-testid='studio-view'>
|
<div
|
||||||
|
className={`studio-clock ${isMirrored ? 'mirror' : ''} ${hideRight ? 'hide-right' : ''}`}
|
||||||
|
data-testid='studio-view'
|
||||||
|
>
|
||||||
<ViewParamsEditor viewOptions={studioClockOptions} />
|
<ViewParamsEditor viewOptions={studioClockOptions} />
|
||||||
<div className='clock-container'>
|
<div className='clock-container'>
|
||||||
{hasAmPm && <div className='clock__ampm'>{hasAmPm}</div>}
|
{hasAmPm && <div className='clock__ampm'>{hasAmPm}</div>}
|
||||||
@@ -114,31 +112,9 @@ export default function StudioClock(props: StudioClockProps) {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='schedule-container'>
|
{!hideRight && (
|
||||||
<div
|
<StudioClockSchedule rundown={backstageEvents} selectedId={selectedId} nextId={nextId} onAir={onAir} />
|
||||||
className={onAir ? 'onAir' : 'onAir onAir--idle'}
|
)}
|
||||||
data-testid={onAir ? 'on-air-enabled' : 'on-air-disabled'}
|
|
||||||
>
|
|
||||||
ON AIR
|
|
||||||
</div>
|
|
||||||
<ul className='schedule'>
|
|
||||||
{trimmedRundown.map((event) => {
|
|
||||||
const start = formatTime(event.timeStart + (event?.delay ?? 0), { format12: 'h:mm a', format24: 'HH:mm' });
|
|
||||||
const isSelected = event.id === selectedId;
|
|
||||||
const isNext = event.id === nextId;
|
|
||||||
const classes = `schedule__item schedule__item${isSelected ? '--now' : isNext ? '--next' : '--future'}`;
|
|
||||||
return (
|
|
||||||
<li key={event.id} className={classes}>
|
|
||||||
<span className='event'>
|
|
||||||
<span className='event__colour' style={{ backgroundColor: `${event.colour}` }} />
|
|
||||||
<SuperscriptTime time={start} />
|
|
||||||
</span>
|
|
||||||
<span>{event.title}</span>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { isOntimeEvent, MaybeString, OntimeEvent, OntimeRundown } from 'ontime-types';
|
||||||
|
|
||||||
|
import { formatTime } from '../../../common/utils/time';
|
||||||
|
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
|
||||||
|
|
||||||
|
import { trimRundown } from './studioClock.utils';
|
||||||
|
|
||||||
|
import './StudioClock.scss';
|
||||||
|
|
||||||
|
interface StudioClockScheduleProps {
|
||||||
|
rundown: OntimeRundown;
|
||||||
|
selectedId: MaybeString;
|
||||||
|
nextId: MaybeString;
|
||||||
|
onAir: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: fit titles on screen
|
||||||
|
const MAX_TITLES = 11;
|
||||||
|
|
||||||
|
export default function StudioClockSchedule(props: StudioClockScheduleProps) {
|
||||||
|
const { rundown, selectedId, nextId, onAir } = props;
|
||||||
|
|
||||||
|
const delayed = rundown.filter((event) => isOntimeEvent(event)) as OntimeEvent[];
|
||||||
|
const trimmedRundown = trimRundown(delayed, selectedId, MAX_TITLES);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='schedule-container'>
|
||||||
|
<div className={onAir ? 'onAir' : 'onAir onAir--idle'} data-testid={onAir ? 'on-air-enabled' : 'on-air-disabled'}>
|
||||||
|
ON AIR
|
||||||
|
</div>
|
||||||
|
<ul className='schedule'>
|
||||||
|
{trimmedRundown.map((event) => {
|
||||||
|
const start = formatTime(event.timeStart + (event?.delay ?? 0), { format12: 'h:mm a', format24: 'HH:mm' });
|
||||||
|
const isSelected = event.id === selectedId;
|
||||||
|
const isNext = event.id === nextId;
|
||||||
|
const classes = `schedule__item schedule__item${isSelected ? '--now' : isNext ? '--next' : '--future'}`;
|
||||||
|
return (
|
||||||
|
<li key={event.id} className={classes}>
|
||||||
|
<span className='event'>
|
||||||
|
<span className='event__colour' style={{ backgroundColor: `${event.colour}` }} />
|
||||||
|
<SuperscriptTime time={start} />
|
||||||
|
</span>
|
||||||
|
<span>{event.title}</span>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { OntimeEvent } from 'ontime-types';
|
import { OntimeEvent } from 'ontime-types';
|
||||||
|
|
||||||
import { secondsInMillis, trimRundown } from '../studioClock.utils';
|
import { trimRundown } from '../studioClock.utils';
|
||||||
|
|
||||||
describe('test trimEventlist function', () => {
|
describe('test trimEventlist function', () => {
|
||||||
const limit = 8;
|
const limit = 8;
|
||||||
@@ -118,14 +118,3 @@ describe('test trimEventlist function', () => {
|
|||||||
expect(l).toStrictEqual(expected);
|
expect(l).toStrictEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('secondsInMillis()', () => {
|
|
||||||
it('return 0 if value is null', () => {
|
|
||||||
expect(secondsInMillis(null)).toBe(0);
|
|
||||||
});
|
|
||||||
it('returns the seconds value of a millis date', () => {
|
|
||||||
const date = 1686255053619; // Thu Jun 08 2023 20:10:53
|
|
||||||
const seconds = secondsInMillis(date);
|
|
||||||
expect(seconds).toBe(53);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -6,4 +6,12 @@ export const getStudioClockOptions = (timeFormat: string): ViewOption[] => [
|
|||||||
getTimeOption(timeFormat),
|
getTimeOption(timeFormat),
|
||||||
{ section: 'Timer Options' },
|
{ section: 'Timer Options' },
|
||||||
hideTimerSeconds,
|
hideTimerSeconds,
|
||||||
|
{ section: 'Element visibility' },
|
||||||
|
{
|
||||||
|
id: 'hideRight',
|
||||||
|
title: 'Hide right section',
|
||||||
|
description: 'Hides the right section with On Air indicator and the schedule',
|
||||||
|
type: 'boolean',
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { MaybeNumber, OntimeEvent } from 'ontime-types';
|
import { OntimeEvent } from 'ontime-types';
|
||||||
import { MILLIS_PER_MINUTE, MILLIS_PER_SECOND } from 'ontime-utils';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Returns trimmed event list array
|
* @description Returns trimmed event list array
|
||||||
@@ -20,15 +19,3 @@ export function trimRundown(rundown: OntimeEvent[], selectedId: string | null, l
|
|||||||
const trimmedRundown = rundown.slice(startIndex, endIndex);
|
const trimmedRundown = rundown.slice(startIndex, endIndex);
|
||||||
return trimmedRundown;
|
return trimmedRundown;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @description Returns amount of seconds in a date given in milliseconds. For studio clock second indicator
|
|
||||||
* @param {MaybeNumber} millis time to format
|
|
||||||
* @returns amount of elapsed seconds
|
|
||||||
*/
|
|
||||||
export function secondsInMillis(millis: MaybeNumber): number {
|
|
||||||
if (!millis) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return Math.floor((millis % MILLIS_PER_MINUTE) / MILLIS_PER_SECOND);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export {
|
|||||||
millisToHours,
|
millisToHours,
|
||||||
millisToMinutes,
|
millisToMinutes,
|
||||||
millisToSeconds,
|
millisToSeconds,
|
||||||
|
secondsInMillis,
|
||||||
} from './src/date-utils/conversionUtils.js';
|
} from './src/date-utils/conversionUtils.js';
|
||||||
export { isTimeString } from './src/date-utils/isTimeString.js';
|
export { isTimeString } from './src/date-utils/isTimeString.js';
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { millisToHours, millisToMinutes, millisToSeconds } from "./conversionUtils";
|
import { millisToHours, millisToMinutes, millisToSeconds, secondsInMillis } from './conversionUtils';
|
||||||
|
|
||||||
describe('millisToSecond()', () => {
|
describe('millisToSecond()', () => {
|
||||||
test('null values', () => {
|
test('null values', () => {
|
||||||
@@ -112,3 +112,14 @@ describe('millisToHours()', () => {
|
|||||||
expect(millisToHours(t.val)).toBe(t.result);
|
expect(millisToHours(t.val)).toBe(t.result);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('secondsInMillis()', () => {
|
||||||
|
it('return 0 if value is null', () => {
|
||||||
|
expect(secondsInMillis(null)).toBe(0);
|
||||||
|
});
|
||||||
|
it('returns the seconds value of a millis date', () => {
|
||||||
|
const date = 1686255053619; // Thu Jun 08 2023 20:10:53
|
||||||
|
const seconds = secondsInMillis(date);
|
||||||
|
expect(seconds).toBe(53);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -64,3 +64,15 @@ export function secondsToMinutes(seconds: number): number {
|
|||||||
export function secondsToHours(seconds: number): number {
|
export function secondsToHours(seconds: number): number {
|
||||||
return Math.floor(seconds / 3600);
|
return Math.floor(seconds / 3600);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Returns amount of seconds in a date given in milliseconds. For studio clock second indicator
|
||||||
|
* @param {MaybeNumber} millis time to format
|
||||||
|
* @returns amount of elapsed seconds
|
||||||
|
*/
|
||||||
|
export function secondsInMillis(millis: MaybeNumber): number {
|
||||||
|
if (!millis) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Math.floor((millis % MILLIS_PER_MINUTE) / MILLIS_PER_SECOND);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user