* chore: upgrade dependencies
* feat/mac: draft pipeline
* feat/mac: use public folder for transient files
* feat/mac: set app fullscreen
* feat/mac: cmd + , toggles menu
* feat/mac: update readme
* refact: easier login process
* refact prevent style issues with safari
* refact reduce css download
* style: cleanup paginator design
* style: studio clock is responsive
* style: fix spacing style issues with safari
This commit is contained in:
Carlos Valente
2022-04-17 20:30:39 +02:00
committed by GitHub
parent 20d3ddbc18
commit db0eee3b9c
140 changed files with 10160 additions and 2139 deletions
@@ -1,105 +0,0 @@
import React, { memo } from 'react';
import PropTypes from 'prop-types';
import style from './PlaybackControl.module.scss';
import StartIconBtn from 'common/components/buttons/StartIconBtn';
import PauseIconBtn from 'common/components/buttons/PauseIconBtn';
import PrevIconBtn from 'common/components/buttons/PrevIconBtn';
import NextIconBtn from 'common/components/buttons/NextIconBtn';
import RollIconBtn from 'common/components/buttons/RollIconBtn';
import UnloadIconBtn from 'common/components/buttons/UnloadIconBtn';
import ReloadIconButton from 'common/components/buttons/ReloadIconBtn';
const areEqual = (prevProps, nextProps) => {
return (
prevProps.playback === nextProps.playback
&& prevProps.selectedId === nextProps.selectedId
&& prevProps.noEvents === nextProps.noEvents
);
};
const Playback = (props) => {
const { playback, selectedId, playbackControl, noEvents } = props;
const isRolling = playback === 'roll';
return (
<div className={style.playbackContainer}>
<StartIconBtn
active={playback === 'start'}
clickhandler={() => playbackControl('start')}
disabled={!selectedId || isRolling || noEvents}
/>
<PauseIconBtn
active={playback === 'pause'}
clickhandler={() => playbackControl('pause')}
disabled={!selectedId || isRolling || noEvents || playback !== 'start'}
/>
<RollIconBtn
active={playback === 'roll'}
disabled={playback === 'roll' || noEvents}
clickhandler={() => playbackControl('roll')}
/>
</div>
);
};
const Transport = (props) => {
const { playback, selectedId, playbackControl, noEvents } = props;
const isRolling = playback === 'roll';
return (
<div className={style.playbackContainer}>
<PrevIconBtn
clickhandler={() => playbackControl('previous')}
disabled={isRolling || noEvents}
/>
<NextIconBtn
clickhandler={() => playbackControl('next')}
disabled={isRolling || noEvents}
/>
<ReloadIconButton
clickhandler={() => playbackControl('reload')}
disabled={selectedId == null || isRolling || noEvents}
/>
<UnloadIconBtn
clickhandler={() => playbackControl('unload')}
disabled={(selectedId == null && !isRolling) || noEvents}
/>
</div>
);
};
const PlaybackButtons = (props) => {
const { playback, selectedId, noEvents, playbackControl } = props;
return (
<>
<Playback
playback={playback}
selectedId={selectedId}
noEvents={noEvents}
playbackControl={playbackControl}
/>
<Transport
playback={playback}
selectedId={selectedId}
noEvents={noEvents}
playbackControl={playbackControl}
/>
</>
);
};
export default memo(PlaybackButtons, areEqual);
PlaybackButtons.propTypes = {
playback: PropTypes.string,
selectedId: PropTypes.string,
playbackControl: PropTypes.func.isRequired,
noEvents: PropTypes.bool.isRequired,
};
Transport.propTypes = {
playback: PropTypes.string,
selectedId: PropTypes.string,
playbackControl: PropTypes.func.isRequired,
noEvents: PropTypes.bool.isRequired,
};
@@ -1,140 +0,0 @@
import React from 'react';
import style from './PlaybackControl.module.scss';
import Countdown from 'common/components/countdown/Countdown';
import { stringFromMillis } from 'ontime-utils/time';
import { Tooltip } from '@chakra-ui/react';
import { Button } from '@chakra-ui/button';
import { memo } from 'react';
import PropTypes from 'prop-types';
const areEqual = (prevProps, nextProps) => {
return (
prevProps.timer.running === nextProps.timer.running &&
prevProps.timer.isNegative === nextProps.timer.isNegative &&
prevProps.timer.expectedFinish === nextProps.timer.expectedFinish &&
prevProps.timer.startedAt === nextProps.timer.startedAt &&
prevProps.playback === nextProps.playback &&
prevProps.timer.secondary === nextProps.timer.secondary &&
prevProps.selectedId === nextProps.selectedId
);
};
const incrementProps = {
size: 'sm',
width: '2.9em',
colorScheme: 'whiteAlpha',
variant: 'outline',
_focus: { boxShadow: 'none' },
};
const PlaybackTimer = (props) => {
const { timer, playback, handleIncrement, selectedId } = props;
const started = stringFromMillis(timer.startedAt, true);
const finish = stringFromMillis(timer.expectedFinish, true);
const isRolling = playback === 'roll';
const isWaiting = timer.secondary > 0 && timer.running == null;
const disableButtons = selectedId == null || isRolling;
return (
<>
<div className={style.timeContainer}>
<div className={style.indicators}>
<Tooltip label='Roll mode active'>
<div className={isRolling ? style.indRollActive : style.indRoll} />
</Tooltip>
<div
className={timer.isNegative ? style.indNegativeActive : style.indNegative}
/>
<div className={style.indDelay} />
</div>
<div className={style.timer}>
<Countdown
time={isWaiting ? timer.secondary : timer.running}
isNegative={timer.isNegative}
small
/>
</div>
{isWaiting ? (
<div className={style.roll}>
<span className={style.rolltag}>Roll: Countdown to start</span>
<span className={style.time}>FIX</span>
</div>
) : (
<>
<div className={style.start}>
<span className={style.tag}>Started at </span>
<span className={style.time}>{started}</span>
</div>
<div className={style.finish}>
<span className={style.tag}>Finish at </span>
<span className={style.time}>{finish}</span>
</div>
</>
)}
<div className={style.btn}>
<Tooltip
label='Remove 1 minute'
delay={500}
shouldWrapChildren={disableButtons}
>
<Button
{...incrementProps}
disabled={disableButtons}
onClick={() => handleIncrement(-1)}
>
-1
</Button>
</Tooltip>
<Tooltip
label='Add 1 minute'
delay={500}
shouldWrapChildren={disableButtons}
>
<Button
{...incrementProps}
disabled={disableButtons}
onClick={() => handleIncrement(1)}
>
+1
</Button>
</Tooltip>
<Tooltip
label='Remove 5 minutes'
delay={500}
shouldWrapChildren={disableButtons}
>
<Button
{...incrementProps}
disabled={disableButtons}
onClick={() => handleIncrement(-5)}
>
-5
</Button>
</Tooltip>
<Tooltip
label='Add 5 minutes'
delay={500}
shouldWrapChildren={disableButtons}
>
<Button
{...incrementProps}
disabled={disableButtons}
onClick={() => handleIncrement(5)}
>
+5
</Button>
</Tooltip>
</div>
</div>
</>
);
};
export default memo(PlaybackTimer, areEqual);
PlaybackTimer.propTypes = {
timer: PropTypes.object.isRequired,
playback: PropTypes.string,
handleIncrement: PropTypes.func.isRequired,
selectedId: PropTypes.string,
};
@@ -1,6 +1,7 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import SocketProvider from 'app/context/socketContext';
import MessageControl from '../MessageControl';
import MessageControl from '../message/MessageControl';
// need to inject the socket provider to make component
// render without failing
@@ -1,6 +1,7 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import SocketProvider from 'app/context/socketContext';
import PlaybackControl from '../PlaybackControl';
import PlaybackControl from '../playback/PlaybackControl';
test('check that playback control renders', async () => {
// need to inject the socket provider to make component
@@ -0,0 +1,35 @@
import React from 'react';
import { Editable, EditableInput, EditablePreview } from '@chakra-ui/editable';
import VisibleIconBtn from '../../../common/components/buttons/VisibleIconBtn';
import style from './MessageControl.module.scss';
const inputProps = {
size: 'sm',
};
export default function InputRow(props) {
const { label, placeholder, text, visible, actionHandler, changeHandler } = props;
return (
<>
<span className={style.label}>{label}</span>
<div className={style.inputItems}>
<Editable
onChange={(event) => changeHandler(event)}
value={text}
placeholder={placeholder}
className={style.inline}
color={text === '' ? '#666' : 'inherit'}
>
<EditablePreview className={style.padleft} />
<EditableInput className={style.padleft} />
</Editable>
<VisibleIconBtn
active={visible || undefined}
actionHandler={actionHandler}
{...inputProps}
/>
</div>
</>
);
}
@@ -1,41 +1,9 @@
import React, { useEffect, useState } from 'react';
import { Editable, EditableInput, EditablePreview } from '@chakra-ui/editable';
import { useSocket } from 'app/context/socketContext';
import VisibleIconBtn from 'common/components/buttons/VisibleIconBtn';
import OnAirIconBtn from '../../common/components/buttons/OnAirIconBtn';
import InputRow from './InputRow';
import OnAirIconBtn from '../../../common/components/buttons/OnAirIconBtn';
import style from './MessageControl.module.scss';
const inputProps = {
size: 'sm',
};
const InputRow = (props) => {
const { label, placeholder, text, visible, actionHandler, changeHandler } = props;
return (
<>
<span className={style.label}>{label}</span>
<div className={style.inputItems}>
<Editable
onChange={(event) => changeHandler(event)}
value={text}
placeholder={placeholder}
className={style.inline}
color={text === '' ? '#666' : 'inherit'}
>
<EditablePreview className={style.padleft} />
<EditableInput className={style.padleft} />
</Editable>
<VisibleIconBtn
active={visible || undefined}
actionHandler={actionHandler}
{...inputProps}
/>
</div>
</>
);
};
export default function MessageControl() {
const socket = useSocket();
const [pres, setPres] = useState({
@@ -1,5 +1,5 @@
@use '../../styles/main' as *;
@use '../../styles/mixins' as *;
@use '../../../styles/main' as *;
@use '../../../styles/mixins' as *;
.messageContainer,
.onAirToggle {
@@ -22,13 +22,13 @@
padding: 0;
margin: 0;
font-size: 0.9em;
color: #ccc;
color: $label-gray;
}
.inline {
border-radius: 4px;
background-color: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.05);
background-color: $input-bg;
border: $input-border;
}
.padleft {
@@ -0,0 +1,38 @@
import React from 'react';
import StartIconBtn from '../../../common/components/buttons/StartIconBtn';
import PauseIconBtn from '../../../common/components/buttons/PauseIconBtn';
import RollIconBtn from '../../../common/components/buttons/RollIconBtn';
import PropTypes from 'prop-types';
import style from './PlaybackControl.module.scss';
export default function Playback(props) {
const { playback, selectedId, playbackControl, noEvents } = props;
const isRolling = playback === 'roll';
return (
<div className={style.playbackContainer}>
<StartIconBtn
active={playback === 'start'}
clickhandler={() => playbackControl('start')}
disabled={!selectedId || isRolling || noEvents}
/>
<PauseIconBtn
active={playback === 'pause'}
clickhandler={() => playbackControl('pause')}
disabled={!selectedId || isRolling || noEvents || playback !== 'start'}
/>
<RollIconBtn
active={playback === 'roll'}
disabled={playback === 'roll' || noEvents}
clickhandler={() => playbackControl('roll')}
/>
</div>
);
}
Playback.propTypes = {
playback: PropTypes.string,
selectedId: PropTypes.string,
playbackControl: PropTypes.func.isRequired,
noEvents: PropTypes.bool.isRequired,
};
@@ -0,0 +1,41 @@
import React, { memo } from 'react';
import PropTypes from 'prop-types';
import Transport from './Transport';
import Playback from './Playback';
const areEqual = (prevProps, nextProps) => {
return (
prevProps.playback === nextProps.playback &&
prevProps.selectedId === nextProps.selectedId &&
prevProps.noEvents === nextProps.noEvents
);
};
const PlaybackButtons = (props) => {
const { playback, selectedId, noEvents, playbackControl } = props;
return (
<>
<Playback
playback={playback}
selectedId={selectedId}
noEvents={noEvents}
playbackControl={playbackControl}
/>
<Transport
playback={playback}
selectedId={selectedId}
noEvents={noEvents}
playbackControl={playbackControl}
/>
</>
);
};
export default memo(PlaybackButtons, areEqual);
PlaybackButtons.propTypes = {
playback: PropTypes.string,
selectedId: PropTypes.string,
playbackControl: PropTypes.func.isRequired,
noEvents: PropTypes.bool.isRequired,
};
@@ -63,7 +63,7 @@ export default function PlaybackControl() {
};
}, [socket]);
const playbackControl = async (action, payload) => {
const playbackControl = async (action) => {
switch (action) {
case 'start':
socket.emit('set-playstate', 'start');
@@ -1,16 +1,16 @@
@use '../../../styles/main' as *;
@use '../../../styles/mixins' as *;
.mainContainer {
width: 100%;
display: flex;
display: grid;
margin: 0 auto;
flex-direction: column;
gap: 5px;
}
.timeContainer,
.playbackContainer {
background-color: rgba(0, 0, 0, 0.05);
border: 1px solid rgba(0, 0, 0, 0.05);
border-radius: 4px;
@include second-container;
padding: 0.5em;
}
@@ -43,7 +43,7 @@
.indRoll,
.indDelay,
.indNegative {
background-color: rgba(0, 0, 0, 0.05);
background-color: $bg-black-300;
}
.indRoll,
@@ -56,7 +56,7 @@
}
.indRollActive {
background-color: #2b6cb0;
background-color: $ontime-roll;
}
.indNegative,
@@ -67,11 +67,11 @@
}
.indNegativeActive {
background-color: #ff7597;
background-color: $ontime-pink;
}
.indDelayActive {
background-color: #dd6b20;
background-color: $ontime-delay;
}
.btn {
@@ -102,17 +102,17 @@
}
.time {
color: #ccc;
color: $header-gray;
font-size: 1.1em;
}
.tag {
color: #aaa;
color: $label-gray;
font-size: 0.9em;
}
.rolltag {
color: #2b6cb0;
color: $ontime-roll;
font-size: 0.9em;
}
@@ -0,0 +1,103 @@
import React, { memo } from 'react';
import Countdown from 'common/components/countdown/Countdown';
import { Tooltip } from '@chakra-ui/react';
import { Button } from '@chakra-ui/button';
import PropTypes from 'prop-types';
import { stringFromMillis } from '../../../common/utils/time';
import style from './PlaybackControl.module.scss';
const areEqual = (prevProps, nextProps) => {
return (
prevProps.timer.running === nextProps.timer.running &&
prevProps.timer.isNegative === nextProps.timer.isNegative &&
prevProps.timer.expectedFinish === nextProps.timer.expectedFinish &&
prevProps.timer.startedAt === nextProps.timer.startedAt &&
prevProps.playback === nextProps.playback &&
prevProps.timer.secondary === nextProps.timer.secondary &&
prevProps.selectedId === nextProps.selectedId
);
};
const incrementProps = {
size: 'sm',
width: '2.9em',
colorScheme: 'whiteAlpha',
variant: 'outline',
_focus: { boxShadow: 'none' },
};
const PlaybackTimer = (props) => {
const { timer, playback, handleIncrement, selectedId } = props;
const started = stringFromMillis(timer.startedAt, true);
const finish = stringFromMillis(timer.expectedFinish, true);
const isRolling = playback === 'roll';
const isWaiting = timer.secondary > 0 && timer.running == null;
const disableButtons = selectedId == null || isRolling;
return (
<div className={style.timeContainer}>
<div className={style.indicators}>
<Tooltip label='Roll mode active'>
<div className={isRolling ? style.indRollActive : style.indRoll} />
</Tooltip>
<div className={timer.isNegative ? style.indNegativeActive : style.indNegative} />
<div className={style.indDelay} />
</div>
<div className={style.timer}>
<Countdown
time={isWaiting ? timer.secondary : timer.running}
isNegative={timer.isNegative}
small
/>
</div>
{isWaiting ? (
<div className={style.roll}>
<span className={style.rolltag}>Roll: Countdown to start</span>
<span className={style.time}>FIX</span>
</div>
) : (
<>
<div className={style.start}>
<span className={style.tag}>Started at </span>
<span className={style.time}>{started}</span>
</div>
<div className={style.finish}>
<span className={style.tag}>Finish at </span>
<span className={style.time}>{finish}</span>
</div>
</>
)}
<div className={style.btn}>
<Tooltip label='Remove 1 minute' delay={500} shouldWrapChildren={disableButtons}>
<Button {...incrementProps} disabled={disableButtons} onClick={() => handleIncrement(-1)}>
-1
</Button>
</Tooltip>
<Tooltip label='Add 1 minute' delay={500} shouldWrapChildren={disableButtons}>
<Button {...incrementProps} disabled={disableButtons} onClick={() => handleIncrement(1)}>
+1
</Button>
</Tooltip>
<Tooltip label='Remove 5 minutes' delay={500} shouldWrapChildren={disableButtons}>
<Button {...incrementProps} disabled={disableButtons} onClick={() => handleIncrement(-5)}>
-5
</Button>
</Tooltip>
<Tooltip label='Add 5 minutes' delay={500} shouldWrapChildren={disableButtons}>
<Button {...incrementProps} disabled={disableButtons} onClick={() => handleIncrement(5)}>
+5
</Button>
</Tooltip>
</div>
</div>
);
};
export default memo(PlaybackTimer, areEqual);
PlaybackTimer.propTypes = {
timer: PropTypes.object.isRequired,
playback: PropTypes.string,
handleIncrement: PropTypes.func.isRequired,
selectedId: PropTypes.string,
};
@@ -0,0 +1,40 @@
import React from 'react';
import PrevIconBtn from '../../../common/components/buttons/PrevIconBtn';
import NextIconBtn from '../../../common/components/buttons/NextIconBtn';
import ReloadIconButton from '../../../common/components/buttons/ReloadIconBtn';
import UnloadIconBtn from '../../../common/components/buttons/UnloadIconBtn';
import PropTypes from 'prop-types';
import style from './PlaybackControl.module.scss';
export default function Transport(props) {
const { playback, selectedId, playbackControl, noEvents } = props;
const isRolling = playback === 'roll';
return (
<div className={style.playbackContainer}>
<PrevIconBtn
clickhandler={() => playbackControl('previous')}
disabled={isRolling || noEvents}
/>
<NextIconBtn
clickhandler={() => playbackControl('next')}
disabled={isRolling || noEvents}
/>
<ReloadIconButton
clickhandler={() => playbackControl('reload')}
disabled={selectedId == null || isRolling || noEvents}
/>
<UnloadIconBtn
clickhandler={() => playbackControl('unload')}
disabled={(selectedId == null && !isRolling) || noEvents}
/>
</div>
);
};
Transport.propTypes = {
playback: PropTypes.string,
selectedId: PropTypes.string,
playbackControl: PropTypes.func.isRequired,
noEvents: PropTypes.bool.isRequired,
};