mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-07 00:13:53 +00:00
Feat/navigate (#81)
* feat/navigate upgrade react router * feat/navigate migrate to react router 6 * feat/navigate style modal * feat/navigate create endpoints for app settings * feat/navigate protect editor with pin * feat/navigate apply dynamic routing draft * feat/navigate upgrade relevant packages * feat/navigate restructure directory and add tests * feat/navigate test aliases validation * feat/navigate validate aliases before sending * feat/navigate create data endpoint * feat/navigate config: prettier * feat/navigate invalidate empty strings * feat/navigate create endpoints * feat/navigate parse on import * feat/navigate navigate to alias * feat/navigate user help and sample data * feat/navigate refact aliases modal * feat/navigate refact settings style * feat/navigate update sample db * feat/navigate link is relative to hostname * feat/navigate navigate to first match * feat/navigate update readme and version bump * feat/navigate config: create shared module * feat/navigate config: cheat module install * feat/navigate fix tests * feat/navigate run tests in pull request * Update ontime_cy.yml
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import EditableTimer from 'common/input/EditableTimer';
|
||||
import { stringFromMillis } from 'ontime-server/utils/time';
|
||||
import { stringFromMillis } from 'ontime-utils/time';
|
||||
import { useContext } from 'react';
|
||||
import { LoggingContext } from '../../../app/context/LoggingContext';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { clamp } from 'app/utils';
|
||||
import { clamp } from 'app/utils/math';
|
||||
import styles from './MyProgressBar.module.css';
|
||||
|
||||
export default function MyProgressBar(props) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import PropTypes from "prop-types";
|
||||
import { Link, Redirect } from 'react-router-dom';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Image } from '@chakra-ui/react';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
@@ -57,7 +57,6 @@ export default function NavLogo(props) {
|
||||
to='/presenter'
|
||||
className={style.navItem}
|
||||
tabIndex={1}
|
||||
onKeyDownCapture={() => <Redirect push to='/presenter' />}
|
||||
>
|
||||
Presenter
|
||||
</Link>
|
||||
@@ -65,7 +64,6 @@ export default function NavLogo(props) {
|
||||
to='/sm'
|
||||
className={style.navItem}
|
||||
tabIndex={2}
|
||||
onKeyDownCapture={() => <Redirect push to='/sm' />}
|
||||
>
|
||||
Backstage
|
||||
</Link>
|
||||
@@ -73,7 +71,6 @@ export default function NavLogo(props) {
|
||||
to='/public'
|
||||
className={style.navItem}
|
||||
tabIndex={3}
|
||||
onKeyDownCapture={() => <Redirect push to='/public' />}
|
||||
>
|
||||
Public
|
||||
</Link>
|
||||
@@ -81,7 +78,6 @@ export default function NavLogo(props) {
|
||||
to='/lower'
|
||||
className={style.navItem}
|
||||
tabIndex={4}
|
||||
onKeyDownCapture={() => <Redirect push to='/lower' />}
|
||||
>
|
||||
Lower Thirds
|
||||
</Link>
|
||||
@@ -89,7 +85,6 @@ export default function NavLogo(props) {
|
||||
to='/pip'
|
||||
className={style.navItem}
|
||||
tabIndex={4}
|
||||
onKeyDownCapture={() => <Redirect push to='/pip' />}
|
||||
>
|
||||
PIP
|
||||
</Link>
|
||||
@@ -97,7 +92,6 @@ export default function NavLogo(props) {
|
||||
to='/studio'
|
||||
className={style.navItem}
|
||||
tabIndex={5}
|
||||
onKeyDownCapture={() => <Redirect push to='/studio' />}
|
||||
>
|
||||
Studio Clock
|
||||
</Link>
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import style from './ProtectRoute.module.scss';
|
||||
import { PinInput, PinInputField } from '@chakra-ui/react';
|
||||
import { IconButton } from '@chakra-ui/button';
|
||||
import { FiCheck } from 'react-icons/fi';
|
||||
import { AppContext } from '../../../app/context/AppContext';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
|
||||
|
||||
export default function ProtectRoute(props) {
|
||||
const isLocal = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
|
||||
const [pin, setPin] = useState('');
|
||||
const [failed, setFailed] = useState(false);
|
||||
const { auth, validate } = useContext(AppContext);
|
||||
|
||||
// Set window title
|
||||
useEffect(() => {
|
||||
document.title = 'ontime';
|
||||
}, []);
|
||||
|
||||
const handleValidation = () => {
|
||||
const r = validate(pin);
|
||||
if (!r) {
|
||||
setFailed(true);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{!isLocal && !auth ? (
|
||||
<div className={style.container}>
|
||||
ontime
|
||||
<div className={failed ? style.pin__failed : style.pin}>
|
||||
<PinInput
|
||||
type='alphanumeric'
|
||||
size='lg'
|
||||
mask
|
||||
onChange={(value) => {
|
||||
setFailed(false);
|
||||
setPin(value);
|
||||
}}
|
||||
>
|
||||
<PinInputField />
|
||||
<PinInputField />
|
||||
<PinInputField />
|
||||
<PinInputField />
|
||||
</PinInput>
|
||||
<IconButton
|
||||
aria-label='Enter'
|
||||
size='lg'
|
||||
isRound
|
||||
icon={<FiCheck />}
|
||||
style={{ fontSize: '1.5em' }}
|
||||
onClick={() => handleValidation()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
props.children
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
ProtectRoute.propTypes = {
|
||||
children: PropTypes.node.isRequired
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
@use '../../../styles/main' as *;
|
||||
@use '../../../styles/mixins' as *;
|
||||
|
||||
.container {
|
||||
background: #222;
|
||||
|
||||
display: grid;
|
||||
place-content: center;
|
||||
height: 100vh;
|
||||
padding-bottom: 30vh;
|
||||
|
||||
color: $ontime-pink;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-weight: 200;
|
||||
text-align: center;
|
||||
font-size: 3vw;
|
||||
}
|
||||
|
||||
.pin,
|
||||
.pin__failed {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
padding: 20px;
|
||||
|
||||
input {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.pin__failed {
|
||||
input {
|
||||
animation: colourFade 1.5s ease;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes colourFade {
|
||||
from {
|
||||
background: $ontime-pink;
|
||||
}
|
||||
to {
|
||||
background: rgba($ontime-pink, 0);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { stringFromMillis } from 'ontime-server/utils/time';
|
||||
import { stringFromMillis } from 'ontime-utils/time';
|
||||
import style from './Paginator.module.css';
|
||||
export default function TodayItem(props) {
|
||||
const { selected, timeStart, timeEnd, title, backstageEvent } = props;
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
isTimeString,
|
||||
timeStringToMillis,
|
||||
} from '../utils/dateConfig';
|
||||
import { stringFromMillis } from 'ontime-server/utils/time';
|
||||
import { stringFromMillis } from 'ontime-utils/time';
|
||||
import style from './EditableTimer.module.css';
|
||||
import { LoggingContext } from '../../app/context/LoggingContext';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { stringFromMillis } from 'ontime-server/utils/time';
|
||||
import { stringFromMillis } from 'ontime-utils/time';
|
||||
|
||||
/**
|
||||
* @description From a list of events, returns only events of type event with calculated delays
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Handles link to external URLs: specifically for a electron / browser case
|
||||
* If electron: ask main process to call a new browser window
|
||||
* If browser: open in new tab
|
||||
* @param url
|
||||
*/
|
||||
export default function handleLink(url) {
|
||||
if (window.process?.type === 'renderer') {
|
||||
window.ipcRenderer.send('send-to-link', url);
|
||||
} else {
|
||||
window.open(url);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user