diff --git a/client/src/features/control/PlaybackButtons.jsx b/client/src/features/control/PlaybackButtons.jsx index 624aff651..3a6452b48 100644 --- a/client/src/features/control/PlaybackButtons.jsx +++ b/client/src/features/control/PlaybackButtons.jsx @@ -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'; diff --git a/client/src/features/control/PlaybackControl.jsx b/client/src/features/control/PlaybackControl.jsx index 996e9f99a..366f3505f 100644 --- a/client/src/features/control/PlaybackControl.jsx +++ b/client/src/features/control/PlaybackControl.jsx @@ -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'; diff --git a/client/src/features/control/PlaybackControl.module.css b/client/src/features/control/PlaybackControl.module.scss similarity index 97% rename from client/src/features/control/PlaybackControl.module.css rename to client/src/features/control/PlaybackControl.module.scss index f1f66cf3d..1010bb00f 100644 --- a/client/src/features/control/PlaybackControl.module.css +++ b/client/src/features/control/PlaybackControl.module.scss @@ -97,6 +97,10 @@ grid-area: fin; } +.roll { + grid-area: 2 / 2 / 2 / 4 ; +} + .time { color: #ccc; font-size: 1.1em; diff --git a/client/src/features/control/PlaybackTimer.jsx b/client/src/features/control/PlaybackTimer.jsx index e2fa3f9da..5e739c759 100644 --- a/client/src/features/control/PlaybackTimer.jsx +++ b/client/src/features/control/PlaybackTimer.jsx @@ -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) => {
-
+
-
+
{ />
{isWaiting ? ( -
+
Roll: Countdown to start {''}
diff --git a/client/src/features/viewers/studio/StudioClock.jsx b/client/src/features/viewers/studio/StudioClock.jsx index fdee31e19..f85c98722 100644 --- a/client/src/features/viewers/studio/StudioClock.jsx +++ b/client/src/features/viewers/studio/StudioClock.jsx @@ -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 (
- +
{time.clockNoSeconds}
{title.titleNext}
-
0 ? style.nextCountdown: style.nextCountdown__overtime}> - {selectedId != null && formatDisplay(time.running)} -
+
0 ? style.nextCountdown : style.nextCountdown__overtime}> + {selectedId != null && formatDisplay(time.running)} +
- {hoursIndicators.map(i => ( + {activeIndicators.map(i => (
) )} - {minutesIndicators.map(i => ( + {secondsIndicators.map(i => (
) )} @@ -75,9 +75,9 @@ export default function StudioClock(props) {
    {schedule.map((s) => (
  • -
    {`${s.time} ${s.title}`} + {`${s.time} ${s.title}`}
  • - )) + )) }
diff --git a/client/src/features/viewers/studio/StudioClock.module.scss b/client/src/features/viewers/studio/StudioClock.module.scss index ebf1f7e53..157db0802 100644 --- a/client/src/features/viewers/studio/StudioClock.module.scss +++ b/client/src/features/viewers/studio/StudioClock.module.scss @@ -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; } } } diff --git a/server/package.json b/server/package.json index 3a1099646..0108bbd63 100644 --- a/server/package.json +++ b/server/package.json @@ -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", diff --git a/server/src/app.js b/server/src/app.js index 6be230698..dcc4b878e 100644 --- a/server/src/app.js +++ b/server/src/app.js @@ -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' diff --git a/server/src/classes/EventTimer.js b/server/src/classes/EventTimer.js index 2d2b16349..7a00dff3e 100644 --- a/server/src/classes/EventTimer.js +++ b/server/src/classes/EventTimer.js @@ -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(); diff --git a/server/src/routes/playbackRouter.js b/server/src/routes/playbackRouter.js index d31d1bc99..a4167fd12 100644 --- a/server/src/routes/playbackRouter.js +++ b/server/src/routes/playbackRouter.js @@ -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);