mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-07 00:13:53 +00:00
Hotfix/4.0.2 (#64)
* hotfix 4.0.2: implement playback router * hotfix 4.0.2: fix studio clock styles * hotfix 4.0.2: broadcast clock always * hotfix 4.0.2: fix overflow in timer control
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { memo } from 'react';
|
||||
import style from './PlaybackControl.module.css';
|
||||
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';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import style from './PlaybackControl.module.css';
|
||||
import style from './PlaybackControl.module.scss';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSocket } from 'app/context/socketContext';
|
||||
import PlaybackButtons from './PlaybackButtons';
|
||||
|
||||
+4
@@ -97,6 +97,10 @@
|
||||
grid-area: fin;
|
||||
}
|
||||
|
||||
.roll {
|
||||
grid-area: 2 / 2 / 2 / 4 ;
|
||||
}
|
||||
|
||||
.time {
|
||||
color: #ccc;
|
||||
font-size: 1.1em;
|
||||
@@ -1,9 +1,9 @@
|
||||
import style from './PlaybackControl.module.css';
|
||||
import style from './PlaybackControl.module.scss';
|
||||
import Countdown from 'common/components/countdown/Countdown';
|
||||
import { stringFromMillis } from 'common/utils/dateConfig';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { Button } from '@chakra-ui/button';
|
||||
import { memo } from 'react';
|
||||
import {stringFromMillis} from 'common/utils/dateConfig';
|
||||
import {Tooltip} from '@chakra-ui/react';
|
||||
import {Button} from '@chakra-ui/button';
|
||||
import {memo} from 'react';
|
||||
|
||||
const areEqual = (prevProps, nextProps) => {
|
||||
return (
|
||||
@@ -16,7 +16,7 @@ const areEqual = (prevProps, nextProps) => {
|
||||
};
|
||||
|
||||
const PlaybackTimer = (props) => {
|
||||
const { timer, playback, handleIncrement } = props;
|
||||
const {timer, playback, handleIncrement} = props;
|
||||
const started = stringFromMillis(timer.startedAt, true);
|
||||
const finish = stringFromMillis(timer.expectedFinish, true);
|
||||
const isNegative = timer.running < 0;
|
||||
@@ -28,7 +28,7 @@ const PlaybackTimer = (props) => {
|
||||
width: '2.9em',
|
||||
colorScheme: 'whiteAlpha',
|
||||
variant: 'outline',
|
||||
_focus: { boxShadow: 'none' },
|
||||
_focus: {boxShadow: 'none'},
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -36,12 +36,12 @@ const PlaybackTimer = (props) => {
|
||||
<div className={style.timeContainer}>
|
||||
<div className={style.indicators}>
|
||||
<Tooltip label='Roll mode active'>
|
||||
<div className={isRolling ? style.indRollActive : style.indRoll} />
|
||||
<div className={isRolling ? style.indRollActive : style.indRoll}/>
|
||||
</Tooltip>
|
||||
<div
|
||||
className={isNegative ? style.indNegativeActive : style.indNegative}
|
||||
/>
|
||||
<div className={style.indDelay} />
|
||||
<div className={style.indDelay}/>
|
||||
</div>
|
||||
<div className={style.timer}>
|
||||
<Countdown
|
||||
@@ -51,7 +51,7 @@ const PlaybackTimer = (props) => {
|
||||
/>
|
||||
</div>
|
||||
{isWaiting ? (
|
||||
<div className={style.start}>
|
||||
<div className={style.roll}>
|
||||
<span className={style.rolltag}>Roll: Countdown to start</span>
|
||||
<span className={style.time}>{''}</span>
|
||||
</div>
|
||||
|
||||
@@ -6,13 +6,13 @@ import {formatDisplay} from "../../../common/utils/dateConfig";
|
||||
import {formatEventList, trimEventlist} from "../../../common/utils/eventsManager";
|
||||
|
||||
export default function StudioClock(props) {
|
||||
const { title, time, backstageEvents, selectedId, nextId, onAir } = props;
|
||||
const { fontSize, ref } = useFitText({maxFontSize:500});
|
||||
const [hoursNow, minutesNow] = time.clockNoSeconds.split(':');
|
||||
const {title, time, backstageEvents, selectedId, nextId, onAir} = props;
|
||||
const {fontSize, ref} = useFitText({maxFontSize: 500});
|
||||
const [, , secondsNow] = time.clock.split(':');
|
||||
const [schedule, setSchedule] = useState([]);
|
||||
|
||||
const hoursIndicators = [...Array(12).keys()];
|
||||
const minutesIndicators = [...Array(60).keys()];
|
||||
const activeIndicators = [...Array(12).keys()];
|
||||
const secondsIndicators = [...Array(60).keys()];
|
||||
const MAX_TITLES = 8;
|
||||
|
||||
// Set window title
|
||||
@@ -35,35 +35,35 @@ export default function StudioClock(props) {
|
||||
|
||||
return (
|
||||
<div className={style.container}>
|
||||
<NavLogo />
|
||||
<NavLogo/>
|
||||
<div className={style.clockContainer}>
|
||||
<div className={style.time}>{time.clockNoSeconds}</div>
|
||||
<div
|
||||
ref={ref}
|
||||
className={style.nextTitle}
|
||||
style={{fontSize, height:'100px', width:'100%', maxWidth:'680px'}}
|
||||
style={{fontSize, height: '100px', width: '100%', maxWidth: '680px'}}
|
||||
>
|
||||
{title.titleNext}
|
||||
</div>
|
||||
<div className={time.running > 0 ? style.nextCountdown: style.nextCountdown__overtime}>
|
||||
{selectedId != null && formatDisplay(time.running)}
|
||||
</div>
|
||||
<div className={time.running > 0 ? style.nextCountdown : style.nextCountdown__overtime}>
|
||||
{selectedId != null && formatDisplay(time.running)}
|
||||
</div>
|
||||
<div className={style.indicators}>
|
||||
{hoursIndicators.map(i => (
|
||||
{activeIndicators.map(i => (
|
||||
<div
|
||||
key = {i}
|
||||
className={i <= hoursNow ? style.hours__active : style.hours}
|
||||
key={i}
|
||||
className={style.hours__active}
|
||||
style={{
|
||||
transform: `rotate(${360/12*i-90}deg) translateX(380px)`
|
||||
transform: `rotate(${360 / 12 * i - 90}deg) translateX(380px)`
|
||||
}}/>
|
||||
)
|
||||
)}
|
||||
{minutesIndicators.map(i => (
|
||||
{secondsIndicators.map(i => (
|
||||
<div
|
||||
key={i}
|
||||
className={i <= minutesNow ? style.min__active : style.min}
|
||||
className={i <= secondsNow ? style.min__active : style.min}
|
||||
style={{
|
||||
transform: `rotate(${360/60*i-90}deg) translateX(415px)`
|
||||
transform: `rotate(${360 / 60 * i - 90}deg) translateX(415px)`
|
||||
}}/>
|
||||
)
|
||||
)}
|
||||
@@ -75,9 +75,9 @@ export default function StudioClock(props) {
|
||||
<ul>
|
||||
{schedule.map((s) => (
|
||||
<li key={s.id} className={s.isNow ? style.now : s.isNext ? style.next : ''}>
|
||||
<div className={s.isNow ? style.decorator__active : s.isNext ? style.decorator__next : style.decorator}/>{`${s.time} ${s.title}`}
|
||||
{`${s.time} ${s.title}`}
|
||||
</li>
|
||||
))
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
height: 100vh;
|
||||
padding: 1vw;
|
||||
|
||||
background: #111;
|
||||
background: #000;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 1000px 1fr;
|
||||
@@ -26,7 +26,7 @@
|
||||
$size-min: 18px;
|
||||
$half-min: 9px;
|
||||
$red-active: #c53030;
|
||||
$red-idle: darken($red-active, 30%);
|
||||
$red-idle: #300000;
|
||||
$cyan-active: #0ff;
|
||||
$cyan-idle: #0aa;
|
||||
|
||||
@@ -46,9 +46,8 @@
|
||||
.time {
|
||||
margin-top: 175px;
|
||||
color: $red-active;
|
||||
font-size: 275px;
|
||||
font-size: 300px;
|
||||
line-height: 0.8em;
|
||||
text-shadow: rgb(180,0,0) 0 0 20px;
|
||||
}
|
||||
.nextTitle:after,
|
||||
.nextCountdown:after,
|
||||
@@ -118,13 +117,11 @@
|
||||
font-family: digital-clock, monospace;
|
||||
text-transform: uppercase;
|
||||
|
||||
|
||||
.onAir,
|
||||
.onAir__idle{
|
||||
padding-bottom: 50px;
|
||||
font-size: 190px;
|
||||
font-size: 170px;
|
||||
line-height: 0.9em;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
.onAir {
|
||||
color: $red-active;
|
||||
@@ -148,30 +145,10 @@
|
||||
gap: 20px;
|
||||
}
|
||||
.now {
|
||||
color: $cyan-active;
|
||||
text-shadow: rgb(0,100,100) 0 0 20px;
|
||||
color: $red-active;
|
||||
}
|
||||
.next {
|
||||
color: $red-active;
|
||||
text-shadow: rgb(100,0,0) 0 0 20px;
|
||||
}
|
||||
.decorator,
|
||||
.decorator__active,
|
||||
.decorator__next {
|
||||
aspect-ratio: 1;
|
||||
border-radius: 50%;
|
||||
background: $red-idle;
|
||||
min-height: $size-hours;
|
||||
max-height: $size-hours;
|
||||
width: $size-hours;
|
||||
}
|
||||
.decorator__active {
|
||||
background: $cyan-active;
|
||||
box-shadow: 0 0 10px 2px rgba(0,255,255,0.25);
|
||||
}
|
||||
.decorator__next{
|
||||
background: $red-active;
|
||||
box-shadow: 0 0 10px 2px rgba(255,0,0,0.25);
|
||||
color: $cyan-active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ontime",
|
||||
"version": "0.4.2",
|
||||
"version": "0.4.3",
|
||||
"author": "Carlos Valente",
|
||||
"description": "Time keeping for live events",
|
||||
"repository": "https://github.com/cpvalente/ontime",
|
||||
@@ -27,7 +27,7 @@
|
||||
"nodestart": "NODE_ENV=development node src/app.js",
|
||||
"setdb": "cp data/db.json src/data/db.json",
|
||||
"clean": "rm -rf ../client/build/ && rm -rf ../client/node_modules && rm -rf src/node_modules && rm -rf ./node_modules && rm -rf ./dist",
|
||||
"prep": "yarn clean && yarn prep",
|
||||
"prep": "yarn clean && yarn setdb",
|
||||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
||||
"start": "NODE_ENV=development electron .",
|
||||
"pack": "electron-builder --dir",
|
||||
|
||||
+4
-2
@@ -57,6 +57,7 @@ await db.write();
|
||||
import { router as eventsRouter } from './routes/eventsRouter.js';
|
||||
import { router as eventRouter } from './routes/eventRouter.js';
|
||||
import { router as ontimeRouter } from './routes/ontimeRouter.js';
|
||||
import { router as playbackRouter } from './routes/playbackRouter.js';
|
||||
|
||||
// Global Objects
|
||||
import { EventTimer } from './classes/EventTimer.js';
|
||||
@@ -81,11 +82,12 @@ app.use('/uploads', express.static('uploads'));
|
||||
app.use('/events', eventsRouter);
|
||||
app.use('/event', eventRouter);
|
||||
app.use('/ontime', ontimeRouter);
|
||||
app.use('/playback', playbackRouter);
|
||||
|
||||
// serve react
|
||||
app.use(
|
||||
express.static(
|
||||
path.join(__dirname, env == 'prod' ? '../' : '../../', 'client/build')
|
||||
path.join(__dirname, env === 'prod' ? '../' : '../../', 'client/build')
|
||||
)
|
||||
);
|
||||
|
||||
@@ -93,7 +95,7 @@ app.get('*', (req, res) => {
|
||||
res.sendFile(
|
||||
path.resolve(
|
||||
__dirname,
|
||||
env == 'prod' ? '../' : '../../',
|
||||
env === 'prod' ? '../' : '../../',
|
||||
'client',
|
||||
'build',
|
||||
'index.html'
|
||||
|
||||
@@ -234,10 +234,22 @@ export class EventTimer extends Timer {
|
||||
}
|
||||
|
||||
update() {
|
||||
// if there is nothing selected, do nothing
|
||||
if (this.selectedEventId == null && this.state !== 'roll') return;
|
||||
const now = this._getCurrentTime();
|
||||
|
||||
// if there is nothing selected, update only clock
|
||||
if (this.selectedEventId == null && this.state !== 'roll') {
|
||||
this.clock = now;
|
||||
this.broadcastThis('timer', {
|
||||
clock: now,
|
||||
running: Timer.toSeconds(this.current),
|
||||
secondary: Timer.toSeconds(this.secondaryTimer),
|
||||
durationSeconds: Timer.toSeconds(this.duration),
|
||||
expectedFinish: this._getExpectedFinish(),
|
||||
startedAt: this._startedAt,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// only implement roll here
|
||||
if (this.state !== 'roll') {
|
||||
super.update();
|
||||
|
||||
@@ -1,38 +1,51 @@
|
||||
import express from 'express';
|
||||
export const router = express.Router();
|
||||
|
||||
// import event controller
|
||||
const playbackController = require('../controllers/playbackController');
|
||||
// import playback controllers
|
||||
import {
|
||||
pbGet,
|
||||
onAir,
|
||||
offAir,
|
||||
pbStart,
|
||||
pbPause,
|
||||
pbStop,
|
||||
pbRoll,
|
||||
pbPrevious,
|
||||
pbNext,
|
||||
pbUnload,
|
||||
pbReload
|
||||
} from '../controllers/playbackController.js';
|
||||
|
||||
// create route between controller and '/playback/' endpoint
|
||||
router.get('/', playbackController.pbGet);
|
||||
router.get('/', pbGet);
|
||||
|
||||
// create route between controller and '/playback/onAir' endpoint
|
||||
router.get('/onAir', playbackController.onAir);
|
||||
router.get('/onAir', onAir);
|
||||
|
||||
// create route between controller and '/playback/offAir' endpoint
|
||||
router.get('/offAir', playbackController.offAir);
|
||||
router.get('/offAir', offAir);
|
||||
|
||||
// create route between controller and '/playback/start' endpoint
|
||||
router.get('/start', playbackController.pbStart);
|
||||
router.get('/start', pbStart);
|
||||
router.get('/play', pbStart);
|
||||
|
||||
// create route between controller and '/playback/pause' endpoint
|
||||
router.get('/pause', playbackController.pbPause);
|
||||
router.get('/pause', pbPause);
|
||||
|
||||
// create route between controller and '/playback/stop' endpoint
|
||||
router.get('/stop', playbackController.pbStop);
|
||||
router.get('/stop', pbStop);
|
||||
|
||||
// create route between controller and '/playback/roll' endpoint
|
||||
router.get('/roll', playbackController.pbRoll);
|
||||
router.get('/roll', pbRoll);
|
||||
|
||||
// create route between controller and '/playback/previous' endpoint
|
||||
router.get('/previous', playbackController.pbPrevious);
|
||||
router.get('/previous', pbPrevious);
|
||||
|
||||
// create route between controller and '/playback/next' endpoint
|
||||
router.get('/next', playbackController.pbNext);
|
||||
router.get('/next', pbNext);
|
||||
|
||||
// create route between controller and '/playback/unload' endpoint
|
||||
router.get('/unload', playbackController.pbUnload);
|
||||
router.get('/unload', pbUnload);
|
||||
|
||||
// create route between controller and '/playback/reload' endpoint
|
||||
router.get('/reload', playbackController.pbReload);
|
||||
router.get('/reload', pbReload);
|
||||
|
||||
Reference in New Issue
Block a user