This commit is contained in:
cv
2021-04-20 12:16:43 +02:00
parent e566424738
commit 2f205bcb55
14 changed files with 291 additions and 194 deletions
@@ -3,7 +3,7 @@ import styles from './MyProgressBar.module.css';
export default function MyProgressBar(props) {
const { now, complete } = props;
const percentComplete = clamp((now * 100) / complete, 0, 100);
const percentComplete = clamp((now * 100) / complete - 1, 0, 100);
return (
<div className={styles.progress}>
@@ -5,10 +5,10 @@
}
.progressBar {
width: 30%;
width: 100%;
height: 2vh;
background-color: rgba(255, 255, 255, 0.79);
border-radius: 4px;
transition: 0.4s linear;
transition-property: width, background-color;
transition: 1s linear;
transition-property: width;
}
@@ -5,7 +5,7 @@
font-weight: 600;
background-color: #ff5b7e;
border: 1px solid rgba(255,255,255,0.47);
border: 1px solid rgba(255,255,255,0.17);
width: 1.5em;
border-radius: 1em;
+127 -115
View File
@@ -1,5 +1,5 @@
import { IconButton } from '@chakra-ui/button';
import { FiSettings } from "react-icons/fi";
import { FiSettings } from 'react-icons/fi';
import { Grid, GridItem, Heading } from '@chakra-ui/layout';
import { Box } from '@chakra-ui/layout';
import NumberedText from '../../common/components/text/NumberedText';
@@ -8,130 +8,142 @@ import MessageControl from '../control/MessageControl';
import PreviewContainer from '../viewers/PreviewContainer';
import styles from './Editor.module.css';
import EventListWrapper from './list/EventListWrapper';
import { useDisclosure } from '@chakra-ui/hooks';
import SettingsModal from '../modals/SettingsModal';
export default function Editor() {
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<Grid
templateRows='1fr 1fr 1fr'
templateColumns='1fr 25vw 25vw 5vw'
gap={5}
className={styles.mainContainer}
>
<GridItem rowSpan={3}>
<Box className={styles.editor} borderRadius='0.5em'>
<Heading size='lg' style={{ paddingBottom: '0.25em' }}>
Event List
</Heading>
<NumberedText number={1} text={'Manage and select event to run'} />
<div className={styles.content}>
<EventListWrapper />
</div>
</Box>
</GridItem>
<>
<SettingsModal isOpen={isOpen} onClose={onClose} />
<GridItem colStart={2} rowStart={2} rowSpan={2} colSpan={2}>
<Box className={styles.editor} borderRadius='0.5em' overflowX='auto'>
<Heading size='lg' style={{ paddingBottom: '0.25em' }}>
Preview Displays
</Heading>
<NumberedText number={4} text={'Realtime screen preview'} />
<div className={styles.content}>
<PreviewContainer />
</div>
</Box>
</GridItem>
<Grid
templateRows='1fr 1fr 1fr'
templateColumns='1fr 25vw 25vw 5vw'
gap={5}
className={styles.mainContainer}
>
<GridItem rowSpan={3}>
<Box className={styles.editor} borderRadius='0.5em'>
<Heading size='lg' style={{ paddingBottom: '0.25em' }}>
Event List
</Heading>
<NumberedText number={1} text={'Manage and select event to run'} />
<div className={styles.content}>
<EventListWrapper />
</div>
</Box>
</GridItem>
<GridItem colStart={2} rowStart={1} rowSpan={1} colSpan={1}>
<Box className={styles.editor} borderRadius='0.5em'>
<Heading size='lg' style={{ paddingBottom: '0.25em' }}>
Display Messages
</Heading>
<NumberedText
number={2}
text={'Show realtime messages on separate screen types'}
/>
<div className={styles.content}>
<MessageControl />
</div>
</Box>
</GridItem>
<GridItem colStart={2} rowStart={2} rowSpan={2} colSpan={2}>
<Box className={styles.editor} borderRadius='0.5em' overflowX='auto'>
<Heading size='lg' style={{ paddingBottom: '0.25em' }}>
Preview Displays
</Heading>
<NumberedText number={4} text={'Realtime screen preview'} />
<div className={styles.content}>
<PreviewContainer />
</div>
</Box>
</GridItem>
<GridItem colStart={3} rowStart={1}>
<Box className={styles.editor} borderRadius='0.5em'>
<Heading size='lg' style={{ paddingBottom: '0.25em' }}>
Time Control
</Heading>
<NumberedText number={3} text={'Control Timer'} />
<div className={styles.content}>
<PlaybackControl />
</div>
</Box>
</GridItem>
<GridItem colStart={2} rowStart={1} rowSpan={1} colSpan={1}>
<Box className={styles.editor} borderRadius='0.5em'>
<Heading size='lg' style={{ paddingBottom: '0.25em' }}>
Display Messages
</Heading>
<NumberedText
number={2}
text={'Show realtime messages on separate screen types'}
/>
<div className={styles.content}>
<MessageControl />
</div>
</Box>
</GridItem>
<GridItem colStart={4} rowSpan={3}>
<Box className={styles.editor} borderRadius='0.5em'>
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '2em',
paddingTop: '3em',
}}
>
<IconButton icon={<FiSettings />} isRound variant='outline' />
<GridItem colStart={3} rowStart={1}>
<Box className={styles.editor} borderRadius='0.5em'>
<Heading size='lg' style={{ paddingBottom: '0.25em' }}>
Time Control
</Heading>
<NumberedText number={3} text={'Control Timer'} />
<div className={styles.content}>
<PlaybackControl />
</div>
</Box>
</GridItem>
<GridItem colStart={4} rowSpan={3}>
<Box className={styles.editor} borderRadius='0.5em'>
<div
style={{
width: 35,
height: 35,
backgroundColor: '#3b8cd8',
borderRadius: '50%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '2em',
paddingTop: '3em',
}}
/>
<div
style={{
width: 35,
height: 35,
backgroundColor: '#3182ce',
borderRadius: '50%',
}}
/>
<div
style={{
width: 35,
height: 35,
backgroundColor: '#2778c4',
borderRadius: '50%',
}}
/>
<div
style={{
width: 35,
height: 35,
backgroundColor: '#1d6eba',
borderRadius: '50%',
}}
/>
<div
style={{
width: 35,
height: 35,
backgroundColor: '#1364b0',
borderRadius: '50%',
}}
/>
<div
style={{
width: 35,
height: 35,
backgroundColor: '#095aa6',
borderRadius: '50%',
}}
/>
</div>
</Box>
</GridItem>
</Grid>
>
<IconButton
icon={<FiSettings />}
isRound
variant='outline'
onClick={onOpen}
/>
<div
style={{
width: 35,
height: 35,
backgroundColor: '#3b8cd8',
borderRadius: '50%',
}}
/>
<div
style={{
width: 35,
height: 35,
backgroundColor: '#3182ce',
borderRadius: '50%',
}}
/>
<div
style={{
width: 35,
height: 35,
backgroundColor: '#2778c4',
borderRadius: '50%',
}}
/>
<div
style={{
width: 35,
height: 35,
backgroundColor: '#1d6eba',
borderRadius: '50%',
}}
/>
<div
style={{
width: 35,
height: 35,
backgroundColor: '#1364b0',
borderRadius: '50%',
}}
/>
<div
style={{
width: 35,
height: 35,
backgroundColor: '#095aa6',
borderRadius: '50%',
}}
/>
</div>
</Box>
</GridItem>
</Grid>
</>
);
}
+1 -5
View File
@@ -164,11 +164,7 @@ export default function SettingsModal(props) {
>
Save
</Button>
<Button
variant='ghost'
onClick={onClose}
disabled={submitting}
>
<Button variant='ghost' onClick={onClose} disabled={submitting}>
Cancel
</Button>
</ModalFooter>
+115 -48
View File
@@ -1,62 +1,129 @@
import { differenceInSeconds, format, subMinutes } from 'date-fns';
import addMinutes from 'date-fns/addMinutes';
import { useContext, useEffect, useState } from 'react';
import { EventContext } from '../../app/context/eventContext';
import { PresenterMessagesContext } from '../../app/context/presenterMessageContext';
import Countdown from '../../common/components/countdown/Countdown';
import MyProgressBar from '../../common/components/myProgressBar/MyProgressBar';
import SmallTimer from '../../common/components/smallTimer/SmallTimer';
import './viewers.css';
import { useEffect, useState } from 'react';
import { useSocket } from '../../app/context/socketContext';
import style from './DefaultPresenter.module.css';
export default function DefaultPresenter() {
const [event] = useContext(EventContext);
const [presMessage] = useContext(PresenterMessagesContext);
const [initialValues, setInitialValues] = useState(null);
const now = new Date();
let values = event ?? {
title: 'Presentation Title',
subtitle: 'Presentation Subtitle',
presenter: 'Presenter Name',
timerDuration: 10,
timeStart: now,
timeEnd: now,
};
const socket = useSocket();
const [pres, setPres] = useState({
text: '',
visible: false,
});
const [publ, setPubl] = useState({
text: '',
visible: false,
});
const [lower, setLower] = useState({
text: '',
visible: false,
});
const [timer, setTimer] = useState({
clock: null,
currentSeconds: null,
startedAt: null,
expectedFinish: null,
});
const [titles, setTitles] = useState({
titleNow: '',
subtitleNow: '',
presenterNow: '',
titleNext: '',
subtitleNext: '',
presenterNext: '',
});
// Ask for update on load
useEffect(() => {
values = event;
}, [event]);
if (socket == null) return;
useEffect(() => {
setInitialValues(event);
}, [event]);
// Handle presenter messages
socket.on('messages-presenter', (data) => {
setPres({ ...data });
});
// NOTE: test only
const clockStarted = addMinutes(now, 6);
// Handle public messages
socket.on('messages-public', (data) => {
setPubl({ ...data });
});
const timer = differenceInSeconds(
now,
subMinutes(clockStarted, values.duration)
);
// Handle lower third messages
socket.on('messages-lower', (data) => {
setLower({ ...data });
});
const timeStart = format(values.timeStart, 'HH:mm');
const currentTime = format(now, 'HH:mm');
const timeEnd = format(values.timeEnd, 'HH:mm');
const elapsed = timer / (values.duration * 60);
// Handle timer
socket.on('timer', (data) => {
setTimer({ ...data });
});
// Handle timer
socket.on('titles', (data) => {
setTitles({ ...data });
});
// Ask for up to date data
socket.emit('get-messages');
// Ask for up to data
socket.emit('get-presenter');
// Ask for up titles
socket.emit('get-titles');
// Clear listeners
return () => {
socket.off('messages-public');
socket.off('messages-presenter');
socket.off('messages-lower');
socket.off('timer');
socket.off('titles');
};
}, [socket]);
return (
<div className='presenter'>
<div className='presentationTitle'>{values.title}</div>
<div className='presentationSub'>{values.subtitle}</div>
<Countdown time={timer} />
{!presMessage.show && <MyProgressBar normalisedComplete={elapsed} />}
<div className={presMessage.show ? 'userMessage' : 'userMessage hidden'}>
{presMessage.text}
<div className={style.mainContainer}>
<div className={style.container}>
<span className={style.label}>Clock: </span>
<span>{timer.clock}</span>
<span className={style.label}>Timer: </span>
<span>{timer.currentSeconds}</span>
<span className={style.label}>Started: </span>
<span>{timer.startedAt}</span>
<span className={style.label}>Finish: </span>
<span>{timer.expectedFinish}</span>
</div>
<div className='extra'>
<SmallTimer label='Scheduled Start' time={timeStart} />
<SmallTimer label='Current Time' time={currentTime} />
<SmallTimer label='Scheduled End' time={timeEnd} />
<div className={style.container}>
<span className={style.label}>Presenter Message: </span>
<span>{pres.text}</span>
<span className={style.label}>Vis: </span>
<span>{pres.visible ? 'visible' : 'invisible'}</span>
</div>
<div className={style.container}>
<span className={style.label}>Public Message: </span>
<span>{publ.text}</span>
<span className={style.label}>Vis: </span>
<span>{publ.visible ? 'visible' : 'invisible'}</span>
</div>
<div className={style.container}>
<span className={style.label}>Lower third Message: </span>
<span>{lower.text}</span>
<span className={style.label}>Vis: </span>
<span>{lower.visible ? 'visible' : 'invisible'}</span>
</div>
<div className={style.container}>
<span className={style.label}>Title Now: </span>
<span>{titles.titleNow}</span>
<span className={style.label}>Subtitle Now: </span>
<span>{titles.subtitleNow}</span>
<span className={style.label}>Presenter Now: </span>
<span>{titles.presenterNow}</span>
</div>
<div className={style.container}>
<span className={style.label}>Title Next: </span>
<span>{titles.titleNext}</span>
<span className={style.label}>Subtitle Next: </span>
<span>{titles.subtitleNext}</span>
<span className={style.label}>Presenter Next: </span>
<span>{titles.presenterNext}</span>
</div>
</div>
);
@@ -0,0 +1,18 @@
.mainContainer {
color: white;
display: flex;
flex-direction: rows;
flex-wrap: wrap;
font-size: 28px;
gap: 2em
}
.container {
flex: 1 0 56%;
display: flex;
}
.label {
padding: 0 1em;
color: #fff5;
}
@@ -1,7 +1,6 @@
import TodayItem from './TodayItem';
import style from './Paginator.module.css';
import { useEffect, useState } from 'react';
import { useTimeout } from '../../../app/hooks/useTimeout';
import { useInterval } from '../../../app/hooks/useInterval';
export default function Paginator(props) {
@@ -23,24 +22,19 @@ export default function Paginator(props) {
useEffect(() => {
if (events == null) return;
console.log('debug events', events);
// how many events in list
let n = events.length;
setNumEvents(n);
console.log('debug ne', n);
// how many paginated views
let p = Math.ceil(n / LIMIT_PER_PAGE);
setPages(p);
console.log('debug np', p);
// divide events in parts of LIMIT_PER_PAGE
const eventStart = LIMIT_PER_PAGE * selPage;
const eventEnd = LIMIT_PER_PAGE * (selPage + 1);
let e = events.slice(eventStart, eventEnd);
setPage(e);
console.log('debug show', e);
// if array is completely in past, show depending on SCROLL_PAST
}, [events, selPage]);
@@ -58,6 +52,7 @@ export default function Paginator(props) {
<div className={style.nav}>
{[...Array(pages)].map((p, i) => (
<div
key={i}
className={i === selPage ? style.navItemSelected : style.navItem}
/>
))}
@@ -69,6 +64,7 @@ export default function Paginator(props) {
else if (selectedYet === 1) selectedYet = 2;
return (
<TodayItem
key={e.id}
selected={selectedYet}
timeStart={e.timeStart}
timeEnd={e.timeEnd}
@@ -12,7 +12,7 @@ export default function TodayItem(props) {
if (selected === 1) selectStyle = style.entryNow;
else if (selected === 2) selectStyle = style.entryFuture;
return (
<div class={selectStyle}>
<div className={selectStyle}>
<div className={style.entryStart}>{start}</div>
<div className={style.entryEnd}>{end}</div>
<div className={style.entryTitle}>{title}</div>
@@ -1,7 +1,6 @@
.container__gray,
.container__grayFinished {
margin: 0;
padding: 0;
box-sizing: border-box; /* reset */
overflow: hidden;
width: 100%; /* restrict the page width to viewport */
@@ -113,7 +112,7 @@
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.85);
z-index: 2;
z-index: -1;
opacity: 0;
transition: 0.5s;
}
@@ -121,6 +120,8 @@
.messageOverlayActive {
opacity: 1;
transition: 0.5s;
transition-property: opacity;
z-index: 2;
}
.message {
+2 -1
View File
@@ -6,12 +6,13 @@ import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
// 1. import `ChakraProvider` component
import { ChakraProvider } from '@chakra-ui/react';
import { ChakraProvider, CSSReset } from '@chakra-ui/react';
ReactDOM.render(
<React.StrictMode>
<ChakraProvider>
<BrowserRouter>
<CSSReset />
<App />
</BrowserRouter>
</ChakraProvider>
+1 -8
View File
@@ -109,7 +109,6 @@ exports.eventsPost = async (req, res) => {
res.sendStatus(201);
} catch (error) {
res.status(400).send(error);
console.log('debug', error);
}
};
@@ -119,19 +118,14 @@ exports.eventsPut = async (req, res) => {
// no valid params
if (!req.body) {
res.status(400).send(`No object found`);
console.log('error here', 'noobj');
return;
}
let eventId = req.body.id;
if (!eventId) {
res.status(400).send(`No id found`);
console.log('error here', 'noid');
res.status(400).send(`Object malformed: id missing`);
return;
}
try {
db.get('events')
.find({ id: req.body.id })
@@ -141,7 +135,6 @@ exports.eventsPut = async (req, res) => {
.then(res.sendStatus(200));
} catch (error) {
res.status(400).send(error);
console.log('error here', error);
}
};
+14 -1
View File
@@ -1,3 +1,16 @@
{
"events": []
"events": [],
"event": {
"title": "",
"url": "",
"publicInfo": "",
"backStageInfo": ""
},
"settings": {
"app": "ontime",
"version": 1,
"osc_enabled": false,
"osc_port": 8008,
"lock": false
}
}
+2 -2
View File
@@ -1,8 +1,8 @@
const express = require('express');
const router = express.Router();
// import playback controller
const eventsController = require('../controllers/eventsController');
// import events controller
const eventsController = require('../controllers/eventsController');
// create route between controller and '/events' endpoint
router.get('/', eventsController.eventsGetAll);