many hotfixes (#465)

* style: disable menu bar in run mode

* fix: external devices in dev mode

* fix: add missing elements to translations

* ux: improve translation strings

* refactor: improve typing

* style: blink on event change

* refactor: param options is object

---------

Co-authored-by: Hannes Rüger <hannesrueger@gmx.de>
This commit is contained in:
Carlos Valente
2023-07-23 15:10:53 +02:00
committed by GitHub
parent bb1eb2838f
commit 31fc222876
15 changed files with 72 additions and 25 deletions
+6 -3
View File
@@ -12,9 +12,12 @@ export const APP_SETTINGS = ['appSettings'];
export const VIEW_SETTINGS = ['viewSettings'];
export const RUNTIME = ['runtimeStore'];
export const serverPort = import.meta.env.DEV ? STATIC_PORT : window.location.port;
export const serverURL = import.meta.env.DEV ? `http://localhost:${serverPort}` : window.location.origin;
export const websocketUrl = `${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.hostname}:${serverPort}/ws`;
const location = window.location;
const socketProtocol = location.protocol === 'https:' ? 'wss' : 'ws';
export const serverPort = import.meta.env.DEV ? STATIC_PORT : location.port;
export const serverURL = import.meta.env.DEV ? `http://${location.hostname}:${serverPort}` : location.origin;
export const websocketUrl = `${socketProtocol}://${location.hostname}:${serverPort}/ws`;
export const eventURL = `${serverURL}/eventdata`;
export const rundownURL = `${serverURL}/events`;
@@ -15,12 +15,12 @@ export default function ParamInput({ paramField }: EditFormInputProps) {
if (type === 'option') {
const optionFromParams = searchParams.get(id);
const defaultOptionValue = paramField.values.find((value) => value === optionFromParams);
const defaultOptionValue = optionFromParams || undefined;
return (
<Select placeholder='Select an option' variant='ontime' name={id} defaultValue={defaultOptionValue}>
{paramField.values.map((value) => (
<option key={value} value={value}>
{Object.entries(paramField.values).map(([key, value]) => (
<option key={key} value={key}>
{value}
</option>
))}
@@ -5,7 +5,7 @@ export const TIME_FORMAT_OPTION: ParamField = {
title: '12 / 24 hour timer',
description: 'Whether to show the time in 12 or 24 hour mode. Overrides the global setting from preferences',
type: 'option',
values: ['12', '24'],
values: { '12': '12 hour AM/PM', '24': '24 hour' },
};
export const CLOCK_OPTIONS: ParamField[] = [
@@ -45,7 +45,7 @@ export const CLOCK_OPTIONS: ParamField[] = [
title: 'Align Horizontal',
description: 'Moves the horizontally in page to start = left | center | end = right',
type: 'option',
values: ['start', 'center', 'end'],
values: { start: 'Start', center: 'Center', end: 'End' },
},
{
id: 'offsetx',
@@ -58,7 +58,7 @@ export const CLOCK_OPTIONS: ParamField[] = [
title: 'Align Vertical',
description: 'Moves the vertically in page to start = left | center | end = right',
type: 'option',
values: ['start', 'center', 'end'],
values: { start: 'Start', center: 'Center', end: 'End' },
},
{
id: 'offsety',
@@ -106,7 +106,7 @@ export const MINIMAL_TIMER_OPTIONS: ParamField[] = [
title: 'Align Horizontal',
description: 'Moves the horizontally in page to start = left | center | end = right',
type: 'option',
values: ['start', 'center', 'end'],
values: { start: 'Start', center: 'Center', end: 'End' },
},
{
id: 'offsetx',
@@ -119,7 +119,7 @@ export const MINIMAL_TIMER_OPTIONS: ParamField[] = [
title: 'Align Vertical',
description: 'Moves the vertically in page to start = left | center | end = right',
type: 'option',
values: ['start', 'center', 'end'],
values: { start: 'Start', center: 'Center', end: 'End' },
},
{
id: 'offsety',
@@ -4,7 +4,7 @@ type BaseField = {
description: string;
};
type OptionsField = { type: 'option'; values: string[] };
type OptionsField = { type: 'option'; values: Record<string, string> };
type StringField = { type: 'string' };
type BooleanField = { type: 'boolean' };
type NumberField = { type: 'number' };
@@ -107,6 +107,7 @@ const MenuBar = (props: MenuBarProps) => {
<div className={style.gap} />
<TooltipActionBtn
{...buttonStyle}
isDisabled={appMode === AppMode.Run}
icon={<IoColorWand />}
className={isQuickStartOpen ? style.open : ''}
clickHandler={onQuickStartOpen}
@@ -115,6 +116,7 @@ const MenuBar = (props: MenuBarProps) => {
/>
<TooltipActionBtn
{...buttonStyle}
isDisabled={appMode === AppMode.Run}
icon={<IoPushOutline />}
className={isUploadOpen ? style.open : ''}
clickHandler={onUploadOpen}
@@ -125,6 +127,7 @@ const MenuBar = (props: MenuBarProps) => {
<TooltipActionBtn
{...buttonStyle}
icon={<IoSaveOutline />}
isDisabled={appMode === AppMode.Run}
clickHandler={downloadRundown}
tooltip='Export project file'
aria-label='Export project file'
@@ -154,6 +157,7 @@ const MenuBar = (props: MenuBarProps) => {
<div className={style.gap} />
<TooltipActionBtn
{...buttonStyle}
isDisabled={appMode === AppMode.Run}
icon={isIntegrationOpen ? <IoExtensionPuzzle /> : <IoExtensionPuzzleOutline />}
className={isIntegrationOpen ? style.open : ''}
clickHandler={onIntegrationOpen}
@@ -163,6 +167,7 @@ const MenuBar = (props: MenuBarProps) => {
/>
<TooltipActionBtn
{...buttonStyle}
isDisabled={appMode === AppMode.Run}
icon={<IoSettingsOutline />}
className={isSettingsOpen ? style.open : ''}
clickHandler={onSettingsOpen}
@@ -1,4 +1,5 @@
@use '../../../theme/viewerDefs' as *;
@use '../../../theme/v2Styles' as *;
.backstage {
margin: 0;
@@ -86,6 +87,10 @@
background-color: var(--card-background-color-override, $viewer-card-bg-color);
padding: 16px 24px;
border-radius: 8px;
&.blink {
animation: blink 0.5s ease-in-out 3;
}
}
.timer-group {
@@ -119,7 +124,7 @@
grid-area: schedule;
overflow: hidden;
height: 100%;
margin-left: clamp(16px, 5vw, 64px);;
margin-left: clamp(16px, 5vw, 64px);
}
.schedule-nav-container {
@@ -143,9 +148,20 @@
}
.qr {
margin-left: clamp(16px, 5vw, 64px);;
margin-left: clamp(16px, 5vw, 64px);
padding: 4px;
background-color: white;
}
}
}
/* =================== AMIMATION ===================*/
@keyframes blink {
0% {
background-color: var(--card-background-color-blink-override, $playback-start);
}
20% {
background-color: var(--card-background-color-override, $viewer-card-bg-color);
}
}
@@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import QRCode from 'react-qr-code';
import { AnimatePresence, motion } from 'framer-motion';
import { EventData, Message, OntimeEvent, ViewSettings } from 'ontime-types';
@@ -43,12 +43,24 @@ export default function Backstage(props: BackstageProps) {
const { isMirrored, publ, title, time, backstageEvents, selectedId, general, viewSettings } = props;
const { shouldRender } = useRuntimeStylesheet(viewSettings?.overrideStyles && overrideStylesURL);
const { getLocalizedString } = useTranslation();
const [blinkClass, setBlinkClass] = useState(false);
// Set window title
useEffect(() => {
document.title = 'ontime - Backstage Screen';
}, []);
// blink on change
useEffect(() => {
setBlinkClass(false);
const timer = setTimeout(() => {
setBlinkClass(true);
}, 10);
return () => clearTimeout(timer);
}, [selectedId]);
// defer rendering until we load stylesheets
if (!shouldRender) {
return null;
@@ -57,7 +69,9 @@ export default function Backstage(props: BackstageProps) {
const clock = formatTime(time.clock, formatOptions);
const startedAt = formatTime(time.startedAt, formatOptions);
const isNegative = (time.current ?? 0) < 0;
const expectedFinish = isNegative ? 'In overtime' : formatTime(time.expectedFinish, formatOptions);
const expectedFinish = isNegative
? getLocalizedString('countdown.overtime')
: formatTime(time.expectedFinish, formatOptions);
const qrSize = Math.max(window.innerWidth / 15, 128);
const filteredEvents = getEventsWithDelay(backstageEvents);
@@ -99,7 +113,7 @@ export default function Backstage(props: BackstageProps) {
<AnimatePresence>
{title.showNow && (
<motion.div
className='event now'
className={`event now ${blinkClass ? 'blink' : ''}`}
key='now'
variants={titleVariants}
initial='hidden'
+2 -1
View File
@@ -1,4 +1,4 @@
import { TranslationObject } from '../Translation.types';
import { TranslationObject } from './en';
export const langDe: TranslationObject = {
'common.end_time': 'Endzeit',
@@ -15,4 +15,5 @@ export const langDe: TranslationObject = {
'countdown.select_event': 'Wählen Sie eine Veranstaltung aus, um sie zu verfolgen',
'countdown.to_start': 'Zeit bis zum Start',
'countdown.waiting': 'Warten auf den Veranstaltungsbeginn',
'countdown.overtime': 'überfällig',
};
@@ -13,4 +13,7 @@ export const langEn = {
'countdown.select_event': 'Select an event to follow',
'countdown.to_start': 'Time to start',
'countdown.waiting': 'Waiting for event start',
'countdown.overtime': 'in overtime',
};
export type TranslationObject = Record<keyof typeof langEn, string>;
+3 -2
View File
@@ -1,4 +1,4 @@
import { TranslationObject } from '../Translation.types';
import { TranslationObject } from './en';
export const langEs: TranslationObject = {
'common.end_time': 'Hora de finalización',
@@ -9,10 +9,11 @@ export const langEs: TranslationObject = {
'common.start_time': 'Hora de inicio',
'common.stage_timer': 'Temporizador de presentador',
'common.started_at': 'Iniciado en',
'common.time_now': 'Hora actual',
'common.time_now': 'Ahora',
'countdown.ended': 'Evento finalizado a las',
'countdown.running': 'Evento en curso',
'countdown.select_event': 'Seleccionar un evento para seguir',
'countdown.to_start': 'Tiempo para comenzar',
'countdown.waiting': 'Esperando el inicio del evento',
'countdown.overtime': 'en tiempo extra',
};
+3 -2
View File
@@ -1,4 +1,4 @@
import { TranslationObject } from '../Translation.types';
import { TranslationObject } from './en';
export const langNo: TranslationObject = {
'common.end_time': 'Sluttid',
@@ -9,10 +9,11 @@ export const langNo: TranslationObject = {
'common.start_time': 'Starttid',
'common.stage_timer': 'Scenetimer',
'common.started_at': 'Startet',
'common.time_now': 'Tid nå',
'common.time_now': 'Klokken nå',
'countdown.ended': 'Hendelse avsluttet',
'countdown.running': 'Hendelse pågår',
'countdown.select_event': 'Velg en hendelse å følge',
'countdown.to_start': 'Tid til start',
'countdown.waiting': 'Venter på start',
'countdown.overtime': 'i overtiden',
};
+2 -1
View File
@@ -1,4 +1,4 @@
import { TranslationObject } from '../Translation.types';
import { TranslationObject } from './en';
export const langPt: TranslationObject = {
'common.end_time': 'Hora de término',
@@ -15,4 +15,5 @@ export const langPt: TranslationObject = {
'countdown.select_event': 'Selecione um evento para acompanhar',
'countdown.to_start': 'Tempo para iniciar',
'countdown.waiting': 'Aguardando o início do evento',
'countdown.overtime': 'em tempo extra',
};
+3 -2
View File
@@ -1,4 +1,4 @@
import { TranslationObject } from '../Translation.types';
import { TranslationObject } from './en';
export const langSv: TranslationObject = {
'common.end_time': 'Sluttid',
@@ -9,10 +9,11 @@ export const langSv: TranslationObject = {
'common.start_time': 'Starttid',
'common.stage_timer': 'Timer för scenen',
'common.started_at': 'Började vid',
'common.time_now': 'Tid nu',
'common.time_now': 'Klockan nu',
'countdown.ended': 'Evenemanget avslutades vid',
'countdown.running': 'Evenemang pågår',
'countdown.select_event': 'Välj ett evenemang att följa',
'countdown.to_start': 'Tid till start',
'countdown.waiting': '"Väntar på att evenemanget ska starta',
'countdown.overtime': 'i övertid',
};
+1
View File
@@ -6,6 +6,7 @@
--label-color-override: #6c6c6c;
--timer-color-override: #202020;
--card-background-color-override: #fff;
--card-background-color-blink-override: #339e4e;
--font-family-override: "Open Sans";
--font-family-bold-override: "Arial Black";
--timer-progress-bg-override: #fff;