mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-23 16:09:11 +00:00
feat: selection
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
"socket.io-client": "^4.0.1",
|
"socket.io-client": "^4.0.1",
|
||||||
|
"tinykeys": "^1.1.2",
|
||||||
"web-vitals": "^1.0.1"
|
"web-vitals": "^1.0.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import VisibleIconBtn from '../../../common/components/buttons/VisibleIconBtn';
|
|||||||
import DeleteIconBtn from '../../../common/components/buttons/DeleteIconBtn';
|
import DeleteIconBtn from '../../../common/components/buttons/DeleteIconBtn';
|
||||||
|
|
||||||
export default function EventBlock(props) {
|
export default function EventBlock(props) {
|
||||||
const { data, selected, delay, index, eventsHandler } = props;
|
const { data, selected, next, delay, index, eventsHandler } = props;
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
|
|
||||||
const [more, setMore] = useState(false);
|
const [more, setMore] = useState(false);
|
||||||
@@ -53,16 +53,13 @@ export default function EventBlock(props) {
|
|||||||
updateValues('presenter', v);
|
updateValues('presenter', v);
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: implement functionality to select next
|
|
||||||
let isNext = false;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={selected ? style.eventRowActive : style.eventRow}>
|
<div className={selected ? style.eventRowActive : style.eventRow}>
|
||||||
<span className={style.drag}>
|
<span className={style.drag}>
|
||||||
<FiMoreVertical />
|
<FiMoreVertical />
|
||||||
</span>
|
</span>
|
||||||
<div className={style.indicators}>
|
<div className={style.indicators}>
|
||||||
<div className={isNext ? style.next : style.nextDisabled}>Next</div>
|
<div className={next ? style.next : style.nextDisabled}>Next</div>
|
||||||
<DelayValue delay={delay} />
|
<DelayValue delay={delay} />
|
||||||
</div>
|
</div>
|
||||||
<EventTimes
|
<EventTimes
|
||||||
|
|||||||
@@ -4,13 +4,56 @@ import BlockBlock from './BlockBlock';
|
|||||||
import EventBlock from './EventBlock';
|
import EventBlock from './EventBlock';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useSocket } from '../../../app/context/socketContext';
|
import { useSocket } from '../../../app/context/socketContext';
|
||||||
|
import tinykeys from 'tinykeys';
|
||||||
import Empty from '../../../common/state/Empty';
|
import Empty from '../../../common/state/Empty';
|
||||||
|
|
||||||
|
|
||||||
export default function EventList(props) {
|
export default function EventList(props) {
|
||||||
const { events, eventsHandler } = props;
|
const { events, eventsHandler } = props;
|
||||||
const socket = useSocket();
|
const socket = useSocket();
|
||||||
const [selected, setSelected] = useState(null);
|
const [selected, setSelected] = useState(null);
|
||||||
|
const [next, setNext] = useState(null);
|
||||||
|
const [cursor, setCursor] = useState(null);
|
||||||
|
|
||||||
|
// Handle keyboard shortcuts
|
||||||
|
useEffect(() => {
|
||||||
|
let unsubscribe = tinykeys(window, {
|
||||||
|
'Shift+ArrowDown': () => {
|
||||||
|
if (cursor == null) setCursor(0);
|
||||||
|
else if (cursor < events.length - 1) setCursor(cursor + 1);
|
||||||
|
},
|
||||||
|
'Shift+ArrowUp': () => {
|
||||||
|
if (cursor == null) setCursor(0);
|
||||||
|
else if (cursor >= 0) setCursor(cursor - 1);
|
||||||
|
},
|
||||||
|
'$mod+Shift+ArrowUp': () => {
|
||||||
|
setCursor(-1);
|
||||||
|
},
|
||||||
|
'Shift+KeyE': (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (cursor == null) return;
|
||||||
|
eventsHandler('add', { type: 'event', order: cursor + 1 });
|
||||||
|
},
|
||||||
|
'Shift+KeyD': (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (cursor == null) return;
|
||||||
|
eventsHandler('add', { type: 'delay', order: cursor + 1 });
|
||||||
|
},
|
||||||
|
'Shift+KeyB': (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (cursor == null) return;
|
||||||
|
eventsHandler('add', { type: 'block', order: cursor + 1 });
|
||||||
|
},
|
||||||
|
'Shift+KeyN': (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (cursor == null) return;
|
||||||
|
if (events[cursor].type === 'event') setNext(cursor);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (cursor > events.length - 1) setCursor(events.length - 1);
|
||||||
|
return () => {
|
||||||
|
unsubscribe();
|
||||||
|
};
|
||||||
|
}, [cursor, events, eventsHandler]);
|
||||||
|
|
||||||
// handle incoming messages
|
// handle incoming messages
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -31,12 +74,11 @@ export default function EventList(props) {
|
|||||||
}, [socket]);
|
}, [socket]);
|
||||||
|
|
||||||
if (events.length < 1) {
|
if (events.length < 1) {
|
||||||
return (
|
return <Empty text='No Events' />;
|
||||||
<Empty text='No Events' />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('EventList: events in event list', events);
|
console.log('EventList: events in event list', events);
|
||||||
|
console.log('Debug: cursor', cursor);
|
||||||
let cumulativeDelay = 0;
|
let cumulativeDelay = 0;
|
||||||
let eventCount = -1;
|
let eventCount = -1;
|
||||||
|
|
||||||
@@ -45,38 +87,50 @@ export default function EventList(props) {
|
|||||||
// -- should i skip the order value and just use the array as order? (checkout dnd)
|
// -- should i skip the order value and just use the array as order? (checkout dnd)
|
||||||
return (
|
return (
|
||||||
<div className={style.eventContainer}>
|
<div className={style.eventContainer}>
|
||||||
|
{cursor === -1 && <div className={style.cursor} />}
|
||||||
|
|
||||||
{events.map((e, index) => {
|
{events.map((e, index) => {
|
||||||
if (e.type === 'event') {
|
if (e.type === 'event') {
|
||||||
eventCount = eventCount + 1;
|
eventCount = eventCount + 1;
|
||||||
return (
|
return (
|
||||||
<EventBlock
|
<>
|
||||||
key={e.id}
|
<EventBlock
|
||||||
index={index}
|
key={e.id}
|
||||||
data={e}
|
index={index}
|
||||||
selected={selected === e.id}
|
data={e}
|
||||||
eventsHandler={eventsHandler}
|
selected={selected === e.id}
|
||||||
delay={cumulativeDelay}
|
next={next === index}
|
||||||
/>
|
eventsHandler={eventsHandler}
|
||||||
|
delay={cumulativeDelay}
|
||||||
|
/>
|
||||||
|
{index === cursor && <div className={style.cursor} />}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
} else if (e.type === 'block') {
|
} else if (e.type === 'block') {
|
||||||
cumulativeDelay = 0;
|
cumulativeDelay = 0;
|
||||||
return (
|
return (
|
||||||
<BlockBlock
|
<>
|
||||||
key={e.id}
|
<BlockBlock
|
||||||
index={index}
|
key={e.id}
|
||||||
data={e}
|
index={index}
|
||||||
eventsHandler={eventsHandler}
|
data={e}
|
||||||
/>
|
eventsHandler={eventsHandler}
|
||||||
|
/>
|
||||||
|
{index === cursor && <div className={style.cursor} />}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
} else if (e.type === 'delay') {
|
} else if (e.type === 'delay') {
|
||||||
cumulativeDelay = cumulativeDelay + e.duration;
|
cumulativeDelay = cumulativeDelay + e.duration;
|
||||||
return (
|
return (
|
||||||
<DelayBlock
|
<>
|
||||||
key={e.id}
|
<DelayBlock
|
||||||
index={index}
|
key={e.id}
|
||||||
data={e}
|
index={index}
|
||||||
eventsHandler={eventsHandler}
|
data={e}
|
||||||
/>
|
eventsHandler={eventsHandler}
|
||||||
|
/>
|
||||||
|
{index === cursor && <div className={style.cursor} />}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -15,3 +15,11 @@
|
|||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cursor {
|
||||||
|
width: 90%;
|
||||||
|
min-height: 2px;
|
||||||
|
background-color: #ff7597;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|||||||
@@ -11657,6 +11657,11 @@ tinycolor2@1.4.2:
|
|||||||
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803"
|
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803"
|
||||||
integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==
|
integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==
|
||||||
|
|
||||||
|
tinykeys@^1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/tinykeys/-/tinykeys-1.1.2.tgz#f9bf567d44e57166a95ac9a6c1d6408e2caa993c"
|
||||||
|
integrity sha512-BFOdq1hPKYrgx98JgnjMuv/unHXqLULfXC9suTeC7yrNFRMGjlZMO1ZL3aF1s6EIYqwkeHkLNe1R3e2F/VoG0A==
|
||||||
|
|
||||||
tmpl@1.0.x:
|
tmpl@1.0.x:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
|
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
|
||||||
|
|||||||
Reference in New Issue
Block a user