mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-08 17:03:53 +00:00
Beta 2 review (#897)
* style: subdue secondary buttons * refactor: remove public message
This commit is contained in:
@@ -24,6 +24,8 @@ interface ScheduleProviderProps {
|
||||
time?: number;
|
||||
}
|
||||
|
||||
const numEventsPerPage = 10;
|
||||
|
||||
export const ScheduleProvider = ({
|
||||
children,
|
||||
events,
|
||||
@@ -37,7 +39,7 @@ export const ScheduleProvider = ({
|
||||
// look for overrides from views
|
||||
const hidePast = isStringBoolean(searchParams.get('hidePast'));
|
||||
const stopCycle = isStringBoolean(searchParams.get('stopCycle'));
|
||||
const eventsPerPage = Number(searchParams.get('eventsPerPage') ?? 7);
|
||||
const eventsPerPage = Number(searchParams.get('eventsPerPage') ?? numEventsPerPage);
|
||||
|
||||
let selectedEventIndex = events.findIndex((event) => event.id === selectedEventId);
|
||||
|
||||
|
||||
@@ -396,7 +396,7 @@ export const getBackstageOptions = (timeFormat: string, customFields: CustomFiel
|
||||
title: 'Events per page',
|
||||
description: 'Sets the number of events on the page, can cause overlow',
|
||||
type: 'number',
|
||||
placeholder: '7 (default)',
|
||||
placeholder: '10 (default)',
|
||||
},
|
||||
{
|
||||
id: 'secondary-src',
|
||||
@@ -433,7 +433,7 @@ export const getPublicOptions = (timeFormat: string, customFields: CustomFields)
|
||||
title: 'Events per page',
|
||||
description: 'Sets the number of events on the page, can cause overlow',
|
||||
type: 'number',
|
||||
placeholder: '7 (default)',
|
||||
placeholder: '10 (default)',
|
||||
},
|
||||
{
|
||||
id: 'secondary-src',
|
||||
|
||||
@@ -25,7 +25,6 @@ export const useOperator = () => {
|
||||
export const useMessageControl = () => {
|
||||
const featureSelector = (state: RuntimeStore) => ({
|
||||
timer: state.message.timer,
|
||||
public: state.message.public,
|
||||
lower: state.message.lower,
|
||||
external: state.message.external,
|
||||
onAir: state.onAir,
|
||||
@@ -37,8 +36,6 @@ export const useMessageControl = () => {
|
||||
export const setMessage = {
|
||||
timerText: (payload: string) => socketSendJson('message', { timer: { text: payload } }),
|
||||
timerVisible: (payload: boolean) => socketSendJson('message', { timer: { visible: payload } }),
|
||||
publicText: (payload: string) => socketSendJson('message', { public: { text: payload } }),
|
||||
publicVisible: (payload: boolean) => socketSendJson('message', { public: { visible: payload } }),
|
||||
lowerText: (payload: string) => socketSendJson('message', { lower: { text: payload } }),
|
||||
lowerVisible: (payload: boolean) => socketSendJson('message', { lower: { visible: payload } }),
|
||||
timerBlink: (payload: boolean) => socketSendJson('message', { timer: { blink: payload } }),
|
||||
|
||||
@@ -23,10 +23,6 @@ export const runtimeStorePlaceholder: RuntimeStore = {
|
||||
blink: false,
|
||||
blackout: false,
|
||||
},
|
||||
public: {
|
||||
text: '',
|
||||
visible: false,
|
||||
},
|
||||
lower: {
|
||||
text: '',
|
||||
visible: false,
|
||||
|
||||
@@ -19,14 +19,6 @@ export default function MessageControl() {
|
||||
const blackout = message.timer.blackout;
|
||||
return (
|
||||
<div className={style.messageContainer}>
|
||||
<InputRow
|
||||
label='Public / Backstage screen message'
|
||||
placeholder='Shown in public and backstage screens'
|
||||
text={message.public.text || ''}
|
||||
visible={message.public.visible || false}
|
||||
changeHandler={(newValue) => setMessage.publicText(newValue)}
|
||||
actionHandler={() => setMessage.publicVisible(!message.public.visible)}
|
||||
/>
|
||||
<InputRow
|
||||
label='Lower third message'
|
||||
placeholder='Shown in lower third'
|
||||
|
||||
@@ -72,6 +72,7 @@ function QuickAddBlock(props: QuickAddBlockProps) {
|
||||
variant='ontime-subtle-white'
|
||||
className={style.quickBtn}
|
||||
leftIcon={<IoAdd />}
|
||||
color='#b1b1b1' // $gray-400
|
||||
>
|
||||
Event
|
||||
</Button>
|
||||
@@ -81,6 +82,7 @@ function QuickAddBlock(props: QuickAddBlockProps) {
|
||||
variant='ontime-subtle-white'
|
||||
className={style.quickBtn}
|
||||
leftIcon={<IoAdd />}
|
||||
color='#b1b1b1' // $gray-400
|
||||
>
|
||||
Delay
|
||||
</Button>
|
||||
@@ -90,6 +92,7 @@ function QuickAddBlock(props: QuickAddBlockProps) {
|
||||
variant='ontime-subtle-white'
|
||||
className={style.quickBtn}
|
||||
leftIcon={<IoAdd />}
|
||||
color='#b1b1b1' // $gray-400
|
||||
>
|
||||
Block
|
||||
</Button>
|
||||
|
||||
@@ -34,7 +34,6 @@ type WithDataProps = {
|
||||
nextId: string | null;
|
||||
onAir: boolean;
|
||||
pres: TimerMessage;
|
||||
publ: Message;
|
||||
publicEventNext: OntimeEvent | null;
|
||||
publicEventNow: OntimeEvent | null;
|
||||
publicSelectedId: string | null;
|
||||
@@ -110,7 +109,6 @@ const withData = <P extends WithDataProps>(Component: ComponentType<P>) => {
|
||||
nextId={nextId}
|
||||
onAir={onAir}
|
||||
pres={message.timer}
|
||||
publ={message.public}
|
||||
publicEventNext={publicEventNext}
|
||||
publicEventNow={publicEventNow}
|
||||
publicSelectedId={publicSelectedId}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
' header header header'
|
||||
' progress progress schedule-nav'
|
||||
' now now schedule'
|
||||
' message message info';
|
||||
' info info schedule';
|
||||
|
||||
/* =================== HEADER + EXTRAS ===================*/
|
||||
|
||||
@@ -33,20 +33,7 @@
|
||||
|
||||
.clock-container {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.public-container {
|
||||
grid-area: message;
|
||||
|
||||
&--hidden {
|
||||
opacity: 0;
|
||||
transition: $viewer-transition-time;
|
||||
transition-property: opacity;
|
||||
}
|
||||
}
|
||||
|
||||
.clock-container,
|
||||
.public-container {
|
||||
.label {
|
||||
font-size: clamp(16px, 1.5vw, 24px);
|
||||
font-weight: 600;
|
||||
@@ -61,11 +48,6 @@
|
||||
letter-spacing: 0.05em;
|
||||
line-height: 0.95em;
|
||||
}
|
||||
|
||||
.message {
|
||||
font-size: clamp(16px, 1.5vw, 24px);
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
/* =================== MAIN - NOW ===================*/
|
||||
@@ -174,4 +156,4 @@
|
||||
100% {
|
||||
background-color: var(--card-background-color-override, $viewer-card-bg-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
|
||||
import QRCode from 'react-qr-code';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { CustomFields, Message, OntimeEvent, ProjectData, Settings, SupportedEvent, ViewSettings } from 'ontime-types';
|
||||
import { CustomFields, OntimeEvent, ProjectData, Settings, SupportedEvent, ViewSettings } from 'ontime-types';
|
||||
import { millisToString, removeLeadingZero } from 'ontime-utils';
|
||||
|
||||
import { overrideStylesURL } from '../../../common/api/constants';
|
||||
@@ -28,7 +28,6 @@ import './Backstage.scss';
|
||||
interface BackstageProps {
|
||||
customFields: CustomFields;
|
||||
isMirrored: boolean;
|
||||
publ: Message;
|
||||
eventNow: OntimeEvent | null;
|
||||
eventNext: OntimeEvent | null;
|
||||
time: ViewExtendedTimer;
|
||||
@@ -43,7 +42,6 @@ export default function Backstage(props: BackstageProps) {
|
||||
const {
|
||||
customFields,
|
||||
isMirrored,
|
||||
publ,
|
||||
eventNow,
|
||||
eventNext,
|
||||
time,
|
||||
@@ -84,7 +82,6 @@ export default function Backstage(props: BackstageProps) {
|
||||
|
||||
const qrSize = Math.max(window.innerWidth / 15, 128);
|
||||
const filteredEvents = backstageEvents.filter((event) => event.type === SupportedEvent.Event);
|
||||
const showPublicMessage = publ.text && publ.visible;
|
||||
const showProgress = time.playback !== 'stop';
|
||||
|
||||
const secondarySource = searchParams.get('secondary-src');
|
||||
@@ -173,11 +170,6 @@ export default function Backstage(props: BackstageProps) {
|
||||
<Schedule isProduction className='schedule-container' />
|
||||
</ScheduleProvider>
|
||||
|
||||
<div className={showPublicMessage ? 'public-container' : 'public-container public-container--hidden'}>
|
||||
<div className='label'>{getLocalizedString('common.public_message')}</div>
|
||||
<div className='message'>{publ.text}</div>
|
||||
</div>
|
||||
|
||||
<div className='info'>
|
||||
{general.backstageUrl && <QRCode value={general.backstageUrl} size={qrSize} level='L' className='qr' />}
|
||||
{general.backstageInfo && <div className='info__message'>{general.backstageInfo}</div>}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
' header header header'
|
||||
' progress progress schedule-nav'
|
||||
' now now schedule'
|
||||
' message message info';
|
||||
' info info schedule';
|
||||
|
||||
/* =================== HEADER + EXTRAS ===================*/
|
||||
|
||||
@@ -33,20 +33,7 @@
|
||||
|
||||
.clock-container {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.public-container {
|
||||
grid-area: message;
|
||||
|
||||
&--hidden {
|
||||
opacity: 0;
|
||||
transition: $viewer-transition-time;
|
||||
transition-property: opacity;
|
||||
}
|
||||
}
|
||||
|
||||
.clock-container,
|
||||
.public-container {
|
||||
.label {
|
||||
font-size: clamp(16px, 1.5vw, 24px);
|
||||
font-weight: 600;
|
||||
@@ -60,11 +47,6 @@
|
||||
letter-spacing: 0.05em;
|
||||
line-height: 0.95em;
|
||||
}
|
||||
|
||||
.message {
|
||||
font-size: clamp(16px, 1.5vw, 24px);
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
/* =================== MAIN - NOW ===================*/
|
||||
@@ -100,7 +82,6 @@
|
||||
grid-area: info;
|
||||
display: flex;
|
||||
gap: max(1vw, 16px);
|
||||
align-self: flex-end;
|
||||
overflow: hidden;
|
||||
|
||||
&__message {
|
||||
@@ -112,7 +93,6 @@
|
||||
}
|
||||
|
||||
.qr {
|
||||
margin-left: clamp(16px, 5vw, 64px);;
|
||||
padding: 4px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import QRCode from 'react-qr-code';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { CustomFields, Message, OntimeEvent, ProjectData, Settings, ViewSettings } from 'ontime-types';
|
||||
import { CustomFields, OntimeEvent, ProjectData, Settings, ViewSettings } from 'ontime-types';
|
||||
|
||||
import { overrideStylesURL } from '../../../common/api/constants';
|
||||
import Schedule from '../../../common/components/schedule/Schedule';
|
||||
@@ -24,7 +24,6 @@ import './Public.scss';
|
||||
interface BackstageProps {
|
||||
customFields: CustomFields;
|
||||
isMirrored: boolean;
|
||||
publ: Message;
|
||||
publicEventNow: OntimeEvent | null;
|
||||
publicEventNext: OntimeEvent | null;
|
||||
time: ViewExtendedTimer;
|
||||
@@ -39,7 +38,6 @@ export default function Public(props: BackstageProps) {
|
||||
const {
|
||||
customFields,
|
||||
isMirrored,
|
||||
publ,
|
||||
publicEventNow,
|
||||
publicEventNext,
|
||||
time,
|
||||
@@ -61,7 +59,6 @@ export default function Public(props: BackstageProps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const showPublicMessage = publ.text && publ.visible;
|
||||
const clock = formatTime(time.clock);
|
||||
const qrSize = Math.max(window.innerWidth / 15, 128);
|
||||
|
||||
@@ -120,11 +117,6 @@ export default function Public(props: BackstageProps) {
|
||||
<Schedule className='schedule-container' />
|
||||
</ScheduleProvider>
|
||||
|
||||
<div className={showPublicMessage ? 'public-container' : 'public-container public-container--hidden'}>
|
||||
<div className='label'>{getLocalizedString('common.public_message')}</div>
|
||||
<div className='message'>{publ.text}</div>
|
||||
</div>
|
||||
|
||||
<div className='info'>
|
||||
{general.publicUrl && <QRCode value={general.publicUrl} size={qrSize} level='L' className='qr' />}
|
||||
{general.publicInfo && <div className='info__message'>{general.publicInfo}</div>}
|
||||
|
||||
@@ -66,7 +66,6 @@ const actionHandlers: Record<string, ActionHandler> = {
|
||||
|
||||
const patch: DeepPartial<MessageState> = {
|
||||
timer: 'timer' in payload ? validateTimerMessage(payload.timer) : undefined,
|
||||
public: 'public' in payload ? validateMessage(payload.public) : undefined,
|
||||
lower: 'lower' in payload ? validateMessage(payload.lower) : undefined,
|
||||
external: 'external' in payload ? validateMessage(payload.external) : undefined,
|
||||
};
|
||||
|
||||
@@ -8,7 +8,6 @@ let instance: MessageService | null = null;
|
||||
|
||||
class MessageService {
|
||||
timer: TimerMessage;
|
||||
public: Message;
|
||||
lower: Message;
|
||||
external: Message;
|
||||
|
||||
@@ -38,11 +37,6 @@ class MessageService {
|
||||
blackout: false,
|
||||
};
|
||||
|
||||
this.public = {
|
||||
text: '',
|
||||
visible: false,
|
||||
};
|
||||
|
||||
this.lower = {
|
||||
text: '',
|
||||
visible: false,
|
||||
@@ -62,7 +56,6 @@ class MessageService {
|
||||
getState(): MessageState {
|
||||
return {
|
||||
timer: this.timer,
|
||||
public: this.public,
|
||||
lower: this.lower,
|
||||
external: this.external,
|
||||
};
|
||||
@@ -70,7 +63,6 @@ class MessageService {
|
||||
|
||||
patch(message: DeepPartial<MessageState>) {
|
||||
if (message.timer) this.timer = { ...this.timer, ...message.timer };
|
||||
if (message.public) this.public = { ...this.public, ...message.public };
|
||||
if (message.lower) this.lower = { ...this.lower, ...message.lower };
|
||||
if (message.external) this.external = { ...this.external, ...message.external };
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ describe('MessageService', () => {
|
||||
it('should patch the message state', () => {
|
||||
const message = {
|
||||
timer: { text: 'new text', visible: true },
|
||||
public: { text: 'public text', visible: false },
|
||||
lower: { text: 'lower text' },
|
||||
external: { visible: true },
|
||||
};
|
||||
@@ -23,7 +22,6 @@ describe('MessageService', () => {
|
||||
|
||||
expect(newState).toEqual({
|
||||
timer: { text: 'new text', visible: true, blackout: false, blink: false },
|
||||
public: { text: 'public text', visible: false },
|
||||
lower: {
|
||||
text: 'lower text',
|
||||
visible: false,
|
||||
@@ -38,14 +36,12 @@ describe('MessageService', () => {
|
||||
it('should not affect other properties when patching', () => {
|
||||
const initialMessage = {
|
||||
timer: { text: 'initial text', visible: true },
|
||||
public: { text: 'public text', visible: false },
|
||||
};
|
||||
|
||||
const newState = messageService.patch(initialMessage);
|
||||
|
||||
expect(newState).toEqual({
|
||||
timer: { text: 'initial text', visible: true, blackout: false, blink: false },
|
||||
public: { text: 'public text', visible: false },
|
||||
lower: {
|
||||
text: '',
|
||||
visible: false,
|
||||
|
||||
@@ -6,15 +6,6 @@ test('message control sends messages to screens', async ({ context }) => {
|
||||
|
||||
await editorPage.goto('http://localhost:4001/messagecontrol');
|
||||
|
||||
// public screen message
|
||||
await editorPage.getByPlaceholder('Shown in public and backstage screens').click();
|
||||
await editorPage.getByPlaceholder('Shown in public and backstage screens').fill('testing public');
|
||||
await editorPage.getByRole('button', { name: 'Toggle Public / Backstage screen message' }).click();
|
||||
|
||||
await featurePage.goto('http://localhost:4001/public');
|
||||
await featurePage.waitForLoadState('load', { timeout: 5000 });
|
||||
await featurePage.getByText('testing public').click({ timeout: 5000 });
|
||||
|
||||
// lower third message
|
||||
await editorPage.getByPlaceholder('Shown in lower third').click();
|
||||
await editorPage.getByPlaceholder('Shown in lower third').fill('testing lower');
|
||||
|
||||
@@ -10,7 +10,6 @@ export type TimerMessage = Message & {
|
||||
|
||||
export type MessageState = {
|
||||
timer: TimerMessage;
|
||||
public: Message;
|
||||
lower: Message;
|
||||
external: Message;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user