mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-15 20:33:47 +00:00
node server + separate client folder
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
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';
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
values = event;
|
||||
}, [event]);
|
||||
|
||||
useEffect(() => {
|
||||
setInitialValues(event);
|
||||
}, [event]);
|
||||
|
||||
// NOTE: test only
|
||||
const clockStarted = addMinutes(now, 6);
|
||||
|
||||
const timer = differenceInSeconds(
|
||||
now,
|
||||
subMinutes(clockStarted, values.timerDuration)
|
||||
);
|
||||
|
||||
const timeStart = format(values.timeStart, 'HH:mm');
|
||||
const currentTime = format(now, 'HH:mm');
|
||||
const timeEnd = format(values.timeEnd, 'HH:mm');
|
||||
const elapsed = timer / (values.timerDuration * 60);
|
||||
|
||||
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>
|
||||
<div className='extra'>
|
||||
<SmallTimer label='Scheduled Start' time={timeStart} />
|
||||
<SmallTimer label='Current Time' time={currentTime} />
|
||||
<SmallTimer label='Scheduled End' time={timeEnd} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { AspectRatio } from '@chakra-ui/layout';
|
||||
import { CircularProgress } from '@chakra-ui/progress';
|
||||
import { useState } from 'react';
|
||||
import style from './IFrameLoader.module.css';
|
||||
|
||||
export default function IFrameLoader(props) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { title, src } = props;
|
||||
|
||||
return (
|
||||
<AspectRatio maxW='300' ratio={16 / 9} className={style.iframeContainer}>
|
||||
<>
|
||||
{loading && (
|
||||
<CircularProgress
|
||||
className={style.loader}
|
||||
isIndeterminate
|
||||
color='orange.300'
|
||||
trackColor='#FFF0'
|
||||
/>
|
||||
)}
|
||||
<iframe
|
||||
className={style.iframe}
|
||||
title={title}
|
||||
src={src}
|
||||
onLoad={() => setLoading(false)}
|
||||
/>
|
||||
</>
|
||||
</AspectRatio>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
.iframeContainer {
|
||||
margin: auto;
|
||||
background-color: #0001;
|
||||
border: 1px solid #0001;
|
||||
}
|
||||
|
||||
.loader {
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.iframe {
|
||||
width: inherit;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import styles from './PreviewContainer.module.css';
|
||||
import IFrameLoader from './IFrameLoader';
|
||||
|
||||
export default function PreviewContainer() {
|
||||
return (
|
||||
<div className={styles.previewContainer}>
|
||||
<div className={styles.previewItem}>
|
||||
<IFrameLoader title='Default Presenter' src='http://localhost:3000/' />
|
||||
<div className={styles.label}>Default Presenter</div>
|
||||
</div>
|
||||
<div className={styles.previewItem}>
|
||||
<IFrameLoader title='Audience' src='http://localhost:3000/' />
|
||||
<div className={styles.label}>Audience</div>
|
||||
</div>
|
||||
<div className={styles.previewItem}>
|
||||
<IFrameLoader title='Stage Manager' src='http://localhost:3000/' />
|
||||
<div className={styles.label}>Stage Manager</div>
|
||||
</div>
|
||||
<div className={styles.previewItem}>
|
||||
<IFrameLoader title='Lower third' src='http://localhost:3000/' />
|
||||
<div className={styles.label}>Lower third</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
.previewContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
.previewItem {
|
||||
width: 45%;
|
||||
}
|
||||
|
||||
.label {
|
||||
padding: 0.1em 4em;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600;800&display=swap');
|
||||
|
||||
.presenter {
|
||||
font-size: 1vh;
|
||||
height: 100%;
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-left: 4vh;
|
||||
}
|
||||
|
||||
.presentationTitle {
|
||||
font-size: 5vw;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.presentationSub {
|
||||
font-size: 3vw;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.userMessage {
|
||||
font-size: 10vw;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.extra {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 3vh;
|
||||
left: 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
}
|
||||
Reference in New Issue
Block a user