mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-16 12:53:32 +00:00
V2 beta3 (#338)
* chore: upgrade local build documentation * style: keep scrolling event in screen * feat: delay is time entry * refactor: remove unused * refactor: remove unused * refactor: batch store updates * refactor: virtually remove cap on events * refactor: style and behaviour tweaks to event block * style: tweaks on schedules * chore: remove sentry from server * style: reorder menu * chore: update docs
This commit is contained in:
@@ -144,8 +144,8 @@ $playback-width: 450px;
|
||||
.eventEditor {
|
||||
border-radius: 8px 8px 0 0;
|
||||
background-color: $bg-container-l2;
|
||||
box-shadow: rgba(0, 0, 0, 0.6) 0 3px 6px 6px;
|
||||
border-top: 1px solid $white-10;
|
||||
box-shadow: rgba(0, 0, 0, 0.35) 0 3px 6px 6px;
|
||||
border-top: 1px solid $white-20;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100vw;
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
display: block;
|
||||
@include input-label;
|
||||
|
||||
.delayLabel {
|
||||
&.delayLabel {
|
||||
color: $ontime-delay-text;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ import { millisToString } from 'ontime-utils';
|
||||
|
||||
import TimeInput from '../../../common/components/input/time-input/TimeInput';
|
||||
import { useEventAction } from '../../../common/hooks/useEventAction';
|
||||
import { millisToMinutes } from '../../../common/utils/dateConfig';
|
||||
import { millisToDelayString } from '../../../common/utils/dateConfig';
|
||||
import { cx } from '../../../common/utils/styleUtils';
|
||||
import { calculateDuration, TimeEntryField, validateEntry } from '../../../common/utils/timesManager';
|
||||
|
||||
import style from '../EventEditor.module.scss';
|
||||
@@ -71,18 +72,15 @@ const EventEditorTimes = (props: EventEditorTimesProps) => {
|
||||
updateEvent(newEventData);
|
||||
};
|
||||
|
||||
const delayed = delay !== 0;
|
||||
const addedTime = delayed ? `${delay >= 0 ? '+' : '-'} ${millisToMinutes(Math.abs(delay))} minutes` : null;
|
||||
const newStart = delayed ? `New start ${millisToString(timeStart + delay)}` : null;
|
||||
const newEnd = delayed ? `New end ${millisToString(timeEnd + delay)}` : null;
|
||||
const delayTime = delay !== 0 ? millisToDelayString(delay) : null;
|
||||
const startLabel = delayTime ? `New start ${millisToString(timeStart + delay)}` : 'Start time';
|
||||
const endLabel = delayTime ? `New end ${millisToString(timeEnd + delay)}` : 'End time';
|
||||
const inputTimeLabels = cx([style.inputLabel, delayTime ? style.delayLabel : null]);
|
||||
|
||||
return (
|
||||
<div className={style.timeOptions}>
|
||||
<div className={style.timers}>
|
||||
<label className={style.inputLabel}>
|
||||
Start time {delayed && <span className={style.delayLabel}>{addedTime}</span>}
|
||||
{delayed && <div className={style.delayLabel}>{newStart}</div>}
|
||||
</label>
|
||||
<label className={inputTimeLabels}>{startLabel}</label>
|
||||
<TimeInput
|
||||
name='timeStart'
|
||||
submitHandler={handleSubmit}
|
||||
@@ -92,10 +90,7 @@ const EventEditorTimes = (props: EventEditorTimesProps) => {
|
||||
placeholder='Start'
|
||||
warning={warning.start}
|
||||
/>
|
||||
<label className={style.inputLabel}>
|
||||
End time {delayed && <span className={style.delayLabel}>{addedTime}</span>}
|
||||
{delayed && <div className={style.delayLabel}>{newEnd}</div>}
|
||||
</label>
|
||||
<label className={inputTimeLabels}>{endLabel}</label>
|
||||
<TimeInput
|
||||
name='timeEnd'
|
||||
submitHandler={handleSubmit}
|
||||
|
||||
@@ -8,8 +8,8 @@ import { IoExtensionPuzzle } from '@react-icons/all-files/io5/IoExtensionPuzzle'
|
||||
import { IoExtensionPuzzleOutline } from '@react-icons/all-files/io5/IoExtensionPuzzleOutline';
|
||||
import { IoScan } from '@react-icons/all-files/io5/IoScan';
|
||||
import { IoSettingsOutline } from '@react-icons/all-files/io5/IoSettingsOutline';
|
||||
import { downloadRundown } from '../../common/api/ontimeApi';
|
||||
|
||||
import { downloadRundown } from '../../common/api/ontimeApi';
|
||||
import QuitIconBtn from '../../common/components/buttons/QuitIconBtn';
|
||||
import TooltipActionBtn from '../../common/components/buttons/TooltipActionBtn';
|
||||
import useElectronEvent from '../../common/hooks/useElectronEvent';
|
||||
@@ -130,31 +130,6 @@ export default function MenuBar(props: MenuBarProps) {
|
||||
isDisabled={!isElectron}
|
||||
/>
|
||||
<div className={style.gap} />
|
||||
<TooltipActionBtn
|
||||
{...buttonStyle}
|
||||
icon={<FiHelpCircle />}
|
||||
clickHandler={() => actionHandler('help')}
|
||||
tooltip='Help'
|
||||
aria-label='Help'
|
||||
/>
|
||||
<TooltipActionBtn
|
||||
{...buttonStyle}
|
||||
icon={<IoSettingsOutline />}
|
||||
className={isSettingsOpen ? style.open : ''}
|
||||
clickHandler={onSettingsOpen}
|
||||
tooltip='Settings'
|
||||
aria-label='Settings'
|
||||
/>
|
||||
<div className={style.gap} />
|
||||
<TooltipActionBtn
|
||||
{...buttonStyle}
|
||||
icon={isIntegrationOpen ? <IoExtensionPuzzle /> : <IoExtensionPuzzleOutline />}
|
||||
className={isIntegrationOpen ? style.open : ''}
|
||||
clickHandler={onIntegrationOpen}
|
||||
tooltip='Integrations'
|
||||
aria-label='Integrations'
|
||||
/>
|
||||
<div className={style.gap} />
|
||||
<TooltipActionBtn
|
||||
{...buttonStyle}
|
||||
icon={<FiUpload />}
|
||||
@@ -170,6 +145,31 @@ export default function MenuBar(props: MenuBarProps) {
|
||||
tooltip='Export showfile'
|
||||
aria-label='Export showfile'
|
||||
/>
|
||||
<div className={style.gap} />
|
||||
<TooltipActionBtn
|
||||
{...buttonStyle}
|
||||
icon={isIntegrationOpen ? <IoExtensionPuzzle /> : <IoExtensionPuzzleOutline />}
|
||||
className={isIntegrationOpen ? style.open : ''}
|
||||
clickHandler={onIntegrationOpen}
|
||||
tooltip='Integrations'
|
||||
aria-label='Integrations'
|
||||
/>
|
||||
<TooltipActionBtn
|
||||
{...buttonStyle}
|
||||
icon={<IoSettingsOutline />}
|
||||
className={isSettingsOpen ? style.open : ''}
|
||||
clickHandler={onSettingsOpen}
|
||||
tooltip='Settings'
|
||||
aria-label='Settings'
|
||||
/>
|
||||
<div className={style.gap} />
|
||||
<TooltipActionBtn
|
||||
{...buttonStyle}
|
||||
icon={<FiHelpCircle />}
|
||||
clickHandler={() => actionHandler('help')}
|
||||
tooltip='Help'
|
||||
aria-label='Help'
|
||||
/>
|
||||
</VStack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { closestCenter, DndContext, DragEndEvent, PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
|
||||
import { arrayMove, SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
||||
import { OntimeRundown, SupportedEvent } from 'ontime-types';
|
||||
import { OntimeRundown, Playback, SupportedEvent } from 'ontime-types';
|
||||
|
||||
import { useEventAction } from '../../common/hooks/useEventAction';
|
||||
import { useRundownEditor } from '../../common/hooks/useSocket';
|
||||
@@ -242,6 +242,7 @@ export default function Rundown(props: RundownProps) {
|
||||
previousEnd={previousEnd}
|
||||
previousEventId={previousEventId}
|
||||
playback={isSelected ? featureData.playback : undefined}
|
||||
isRolling={featureData.playback === Playback.Roll}
|
||||
/>
|
||||
{((showQuickEntry && index === cursor) || isLast) && (
|
||||
<QuickAddBlock
|
||||
|
||||
@@ -26,10 +26,23 @@ interface RundownEntryProps {
|
||||
previousEnd: number;
|
||||
previousEventId?: string;
|
||||
playback?: Playback; // we only care about this if this event is playing
|
||||
isRolling: boolean; // we need to know even if not related to this event
|
||||
}
|
||||
|
||||
export default function RundownEntry(props: RundownEntryProps) {
|
||||
const { index, eventIndex, data, selected, hasCursor, next, delay, previousEnd, previousEventId, playback } = props;
|
||||
const {
|
||||
index,
|
||||
eventIndex,
|
||||
data,
|
||||
selected,
|
||||
hasCursor,
|
||||
next,
|
||||
delay,
|
||||
previousEnd,
|
||||
previousEventId,
|
||||
playback,
|
||||
isRolling,
|
||||
} = props;
|
||||
const { emitError } = useEmitLog();
|
||||
const { addEvent, updateEvent, deleteEvent } = useEventAction();
|
||||
|
||||
@@ -149,6 +162,7 @@ export default function RundownEntry(props: RundownEntryProps) {
|
||||
selected={selected}
|
||||
hasCursor={hasCursor}
|
||||
playback={playback}
|
||||
isRolling={isRolling}
|
||||
actionHandler={actionHandler}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -23,7 +23,7 @@ $block-cursor-color: $blue-400;
|
||||
}
|
||||
|
||||
@mixin block-spacing() {
|
||||
padding: 4px 8px 4px 2px;
|
||||
padding-right: 8px;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { Button, HStack } from '@chakra-ui/react';
|
||||
import { useSortable } from '@dnd-kit/sortable';
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
@@ -9,7 +9,6 @@ import { OntimeDelay, OntimeEvent } from 'ontime-types';
|
||||
|
||||
import DelayInput from '../../../common/components/input/delay-input/DelayInput';
|
||||
import { useEventAction } from '../../../common/hooks/useEventAction';
|
||||
import { millisToMinutes } from '../../../common/utils/dateConfig';
|
||||
import { cx } from '../../../common/utils/styleUtils';
|
||||
import BlockActionMenu from '../event-block/composite/BlockActionMenu';
|
||||
import { EventItemActions } from '../RundownEntry';
|
||||
@@ -32,7 +31,7 @@ interface DelayBlockProps {
|
||||
|
||||
export default function DelayBlock(props: DelayBlockProps) {
|
||||
const { data, hasCursor, actionHandler } = props;
|
||||
const { applyDelay, updateEvent, deleteEvent } = useEventAction();
|
||||
const { applyDelay, deleteEvent } = useEventAction();
|
||||
const handleRef = useRef<null | HTMLSpanElement>(null);
|
||||
|
||||
const {
|
||||
@@ -65,28 +64,14 @@ export default function DelayBlock(props: DelayBlockProps) {
|
||||
deleteEvent(data.id);
|
||||
};
|
||||
|
||||
const delaySubmitHandler = useCallback(
|
||||
(value: number) => {
|
||||
const newEvent = {
|
||||
id: data.id,
|
||||
duration: value * 60000,
|
||||
};
|
||||
|
||||
updateEvent(newEvent);
|
||||
},
|
||||
[data.id, updateEvent],
|
||||
);
|
||||
|
||||
const blockClasses = cx([style.delay, hasCursor ? style.hasCursor : null]);
|
||||
|
||||
const delayValue = data.duration != null ? millisToMinutes(data.duration) : undefined;
|
||||
|
||||
return (
|
||||
<div className={blockClasses} ref={setNodeRef} style={dragStyle}>
|
||||
<span className={style.drag} ref={handleRef} {...dragAttributes} {...dragListeners}>
|
||||
<IoReorderTwo />
|
||||
</span>
|
||||
<DelayInput value={delayValue} submitHandler={delaySubmitHandler} />
|
||||
<DelayInput eventId={data.id} duration={data.duration} />
|
||||
<HStack spacing='8px' className={style.actionOverlay}>
|
||||
<Button onClick={applyDelayHandler} size='sm' leftIcon={<IoCheckmark />} variant='ontime-subtle-white'>
|
||||
Apply
|
||||
|
||||
@@ -22,10 +22,30 @@ $skip-opacity: 0.1;
|
||||
padding-right: $block-clearance;
|
||||
gap: 2px;
|
||||
|
||||
@mixin declare-overrides(){
|
||||
--status-color-override: #{$gray-200};
|
||||
--status-color-active-override: #{$green-400};
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: $gray-1350;
|
||||
}
|
||||
|
||||
&.play {
|
||||
background-color: $green-700;
|
||||
@include declare-overrides;
|
||||
}
|
||||
|
||||
&.roll {
|
||||
background-color: $blue-700;
|
||||
@include declare-overrides;
|
||||
}
|
||||
|
||||
&.pause {
|
||||
background-color: $orange-700;
|
||||
@include declare-overrides;
|
||||
}
|
||||
|
||||
&.hasCursor {
|
||||
outline: 1px solid $block-cursor-color;
|
||||
}
|
||||
@@ -146,6 +166,7 @@ $skip-opacity: 0.1;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: var(--status-color-override, $gray-500);
|
||||
|
||||
.tag {
|
||||
padding-top: 1px;
|
||||
@@ -156,12 +177,12 @@ $skip-opacity: 0.1;
|
||||
.statusIcon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: $gray-500;
|
||||
}
|
||||
|
||||
.statusIcon.active {
|
||||
color: $active-indicator;
|
||||
color: var(--status-color-active-override, $active-indicator);
|
||||
}
|
||||
|
||||
.statusIcon.disabled {
|
||||
color: $gray-1000;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ interface EventBlockProps {
|
||||
selected: boolean;
|
||||
hasCursor: boolean;
|
||||
playback?: Playback;
|
||||
isRolling: boolean;
|
||||
actionHandler: (
|
||||
action: EventItemActions,
|
||||
payload?:
|
||||
@@ -65,6 +66,7 @@ export default function EventBlock(props: EventBlockProps) {
|
||||
selected,
|
||||
hasCursor,
|
||||
playback,
|
||||
isRolling,
|
||||
actionHandler,
|
||||
} = props;
|
||||
|
||||
@@ -128,6 +130,7 @@ export default function EventBlock(props: EventBlockProps) {
|
||||
style.eventBlock,
|
||||
skip ? style.skip : null,
|
||||
selected ? style.selected : null,
|
||||
playback ? style[playback] : null,
|
||||
hasCursor ? style.hasCursor : null,
|
||||
]);
|
||||
|
||||
@@ -157,6 +160,7 @@ export default function EventBlock(props: EventBlockProps) {
|
||||
skip={skip}
|
||||
selected={selected}
|
||||
playback={playback}
|
||||
isRolling={isRolling}
|
||||
actionHandler={actionHandler}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { memo, useCallback, useEffect, useState } from 'react';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { IoCaretDown } from '@react-icons/all-files/io5/IoCaretDown';
|
||||
import { IoCaretUp } from '@react-icons/all-files/io5/IoCaretUp';
|
||||
import { IoArrowDown } from '@react-icons/all-files/io5/IoArrowDown';
|
||||
import { IoArrowUp } from '@react-icons/all-files/io5/IoArrowUp';
|
||||
import { IoOptions } from '@react-icons/all-files/io5/IoOptions';
|
||||
import { IoPeople } from '@react-icons/all-files/io5/IoPeople';
|
||||
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
|
||||
@@ -49,6 +49,7 @@ interface EventBlockInnerProps {
|
||||
skip: boolean;
|
||||
selected: boolean;
|
||||
playback?: Playback;
|
||||
isRolling: boolean;
|
||||
actionHandler: (action: EventItemActions, payload?: any) => void;
|
||||
}
|
||||
|
||||
@@ -70,6 +71,7 @@ const EventBlockInner = (props: EventBlockInnerProps) => {
|
||||
skip = false,
|
||||
selected,
|
||||
playback,
|
||||
isRolling,
|
||||
actionHandler,
|
||||
} = props;
|
||||
|
||||
@@ -89,17 +91,18 @@ const EventBlockInner = (props: EventBlockInnerProps) => {
|
||||
}
|
||||
}, [eventId, isOpen, removeOpenEvent, setOpenEvent]);
|
||||
|
||||
const eventIsPlaying = selected && playback === Playback.Play;
|
||||
const eventIsPlaying = playback === Playback.Play;
|
||||
const eventIsPaused = playback === Playback.Pause;
|
||||
|
||||
const playBtnStyles = { _hover: {} };
|
||||
if (!skip && eventIsPlaying) {
|
||||
playBtnStyles._hover = { bg: '#c05621' };
|
||||
playBtnStyles._hover = { bg: '#c05621' }; // $ontime-paused
|
||||
} else if (!skip && !eventIsPlaying) {
|
||||
playBtnStyles._hover = {};
|
||||
}
|
||||
|
||||
return !renderInner ? null : (
|
||||
<>
|
||||
<EventBlockPlayback eventId={eventId} skip={skip} isPlaying={eventIsPlaying} selected={selected} />
|
||||
<EventBlockTimers
|
||||
eventId={eventId}
|
||||
timeStart={timeStart}
|
||||
@@ -109,6 +112,14 @@ const EventBlockInner = (props: EventBlockInnerProps) => {
|
||||
previousEnd={previousEnd}
|
||||
/>
|
||||
<EditableBlockTitle title={title} eventId={eventId} placeholder='Event title' className={style.eventTitle} />
|
||||
<EventBlockPlayback
|
||||
eventId={eventId}
|
||||
skip={skip}
|
||||
isPlaying={eventIsPlaying}
|
||||
isPaused={eventIsPaused}
|
||||
selected={selected}
|
||||
disablePlayback={skip || isRolling}
|
||||
/>
|
||||
<div className={style.statusElements}>
|
||||
<span className={style.eventNote}>{note}</span>
|
||||
<div className={selected ? style.progressBg : `${style.progressBg} ${style.hidden}`}>
|
||||
@@ -175,10 +186,10 @@ function EndActionIcon(props: { action: EndAction; className: string }) {
|
||||
function TimerIcon(props: { type: TimerType; className: string }) {
|
||||
const { type, className } = props;
|
||||
if (type === TimerType.CountUp) {
|
||||
return <IoCaretUp className={className} />;
|
||||
return <IoArrowUp className={className} />;
|
||||
}
|
||||
if (type === TimerType.Clock) {
|
||||
return <IoTime className={className} />;
|
||||
}
|
||||
return <IoCaretDown className={className} />;
|
||||
return <IoArrowDown className={className} />;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { memo } from 'react';
|
||||
import { IoPause } from '@react-icons/all-files/io5/IoPause';
|
||||
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
|
||||
import { IoPlayOutline } from '@react-icons/all-files/io5/IoPlayOutline';
|
||||
import { IoReload } from '@react-icons/all-files/io5/IoReload';
|
||||
import { IoRemoveCircle } from '@react-icons/all-files/io5/IoRemoveCircle';
|
||||
import { IoRemoveCircleOutline } from '@react-icons/all-files/io5/IoRemoveCircleOutline';
|
||||
@@ -16,6 +16,13 @@ const blockBtnStyle = {
|
||||
size: 'sm',
|
||||
};
|
||||
|
||||
type StyleVariant = {
|
||||
'aria-label': string;
|
||||
tooltip: string;
|
||||
backgroundColor: string;
|
||||
_hover: { backgroundColor?: string };
|
||||
};
|
||||
|
||||
const tooltipProps = {
|
||||
openDelay: tooltipDelayMid,
|
||||
};
|
||||
@@ -24,17 +31,55 @@ interface EventBlockPlaybackProps {
|
||||
eventId: string;
|
||||
skip: boolean;
|
||||
isPlaying: boolean;
|
||||
isPaused: boolean;
|
||||
selected: boolean;
|
||||
disablePlayback: boolean;
|
||||
}
|
||||
|
||||
const EventBlockPlayback = (props: EventBlockPlaybackProps) => {
|
||||
const { eventId, skip, isPlaying, selected } = props;
|
||||
const { eventId, skip, isPlaying, isPaused, selected, disablePlayback } = props;
|
||||
const { updateEvent } = useEventAction();
|
||||
|
||||
const toggleSkip = () => {
|
||||
updateEvent({ id: eventId, skip: !skip });
|
||||
};
|
||||
|
||||
const actionHandler = () => {
|
||||
// is playing -> pause
|
||||
// is paused -> continue
|
||||
// otherwise -> start
|
||||
if (isPlaying) {
|
||||
setEventPlayback.pause();
|
||||
} else if (isPaused) {
|
||||
setEventPlayback.start();
|
||||
} else {
|
||||
setEventPlayback.startEvent(eventId);
|
||||
}
|
||||
};
|
||||
|
||||
const buttonVariant: Partial<StyleVariant> = {};
|
||||
|
||||
if (isPaused) {
|
||||
// continue
|
||||
buttonVariant['aria-label'] = 'Continue event';
|
||||
buttonVariant.tooltip = 'Continue event';
|
||||
buttonVariant.backgroundColor = '#339E4E';
|
||||
buttonVariant._hover = { backgroundColor: '#339E4Eee' };
|
||||
} else if (isPlaying) {
|
||||
// pause
|
||||
buttonVariant['aria-label'] = 'Pause event';
|
||||
buttonVariant.tooltip = 'Pause event';
|
||||
buttonVariant.backgroundColor = '#c05621';
|
||||
buttonVariant._hover = { backgroundColor: '#c05621ee' };
|
||||
} else {
|
||||
// start
|
||||
buttonVariant['aria-label'] = 'Start event';
|
||||
buttonVariant.tooltip = 'Start event';
|
||||
if (!disablePlayback) {
|
||||
buttonVariant._hover = { backgroundColor: '#339E4E' };
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={style.playbackActions}>
|
||||
<TooltipActionBtn
|
||||
@@ -55,7 +100,7 @@ const EventBlockPlayback = (props: EventBlockPlaybackProps) => {
|
||||
aria-label='Load event'
|
||||
tooltip='Load event'
|
||||
icon={<IoReload className={style.flip} />}
|
||||
isDisabled={skip}
|
||||
isDisabled={disablePlayback}
|
||||
{...tooltipProps}
|
||||
{...blockBtnStyle}
|
||||
clickHandler={() => setEventPlayback.loadEvent(eventId)}
|
||||
@@ -65,13 +110,12 @@ const EventBlockPlayback = (props: EventBlockPlaybackProps) => {
|
||||
variant='ontime-subtle-white'
|
||||
aria-label='Start event'
|
||||
tooltip='Start event'
|
||||
icon={isPlaying ? <IoPlay /> : <IoPlayOutline />}
|
||||
isDisabled={skip}
|
||||
icon={!isPlaying ? <IoPlay /> : <IoPause />}
|
||||
isDisabled={disablePlayback}
|
||||
{...tooltipProps}
|
||||
{...blockBtnStyle}
|
||||
clickHandler={() => setEventPlayback.startEvent(eventId)}
|
||||
backgroundColor={isPlaying ? '#58A151' : undefined}
|
||||
_hover={{ backgroundColor: isPlaying ? '#58A151' : undefined }}
|
||||
{...buttonVariant}
|
||||
clickHandler={actionHandler}
|
||||
tabIndex={-1}
|
||||
/>
|
||||
</div>
|
||||
|
||||
+4
-6
@@ -1,12 +1,10 @@
|
||||
@use '../../../../theme/v2Styles' as *;
|
||||
|
||||
.progressBar {
|
||||
// layout
|
||||
height: 100%;
|
||||
width: 0;
|
||||
border-radius: 1px 0 0 1px;
|
||||
|
||||
// animations
|
||||
transition: 1s linear;
|
||||
transition-property: width;
|
||||
|
||||
@@ -14,6 +12,10 @@
|
||||
background-color: $playback-start;
|
||||
}
|
||||
|
||||
&.overtime {
|
||||
background-color: $playback-negative;
|
||||
}
|
||||
|
||||
&.pause {
|
||||
background-color: $ontime-paused;
|
||||
}
|
||||
@@ -21,8 +23,4 @@
|
||||
&.roll {
|
||||
background-color: $ontime-roll;
|
||||
}
|
||||
|
||||
&.overtime {
|
||||
background-color: $playback-negative;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { millisToString } from 'ontime-utils';
|
||||
|
||||
import TimeInput from '../../../../common/components/input/time-input/TimeInput';
|
||||
import { useEventAction } from '../../../../common/hooks/useEventAction';
|
||||
import { millisToMinutes } from '../../../../common/utils/dateConfig';
|
||||
import { millisToDelayString } from '../../../../common/utils/dateConfig';
|
||||
import { calculateDuration, TimeEntryField, validateEntry } from '../../../../common/utils/timesManager';
|
||||
|
||||
import style from '../EventBlock.module.scss';
|
||||
@@ -64,8 +64,9 @@ const EventBlockTimers = (props: EventBlockTimerProps) => {
|
||||
[timeEnd, timeStart],
|
||||
);
|
||||
|
||||
const delayTime = `${delay >= 0 ? '+' : '-'} ${millisToMinutes(Math.abs(delay))}`;
|
||||
const newTime = millisToString(timeStart + delay);
|
||||
const delayedStart = Math.max(0, timeStart + delay);
|
||||
const newTime = millisToString(delayedStart);
|
||||
const delayTime = delay !== 0 ? millisToDelayString(delay) : null;
|
||||
|
||||
return (
|
||||
<div className={style.eventTimers}>
|
||||
@@ -94,13 +95,14 @@ const EventBlockTimers = (props: EventBlockTimerProps) => {
|
||||
submitHandler={handleSubmit}
|
||||
validationHandler={handleValidation}
|
||||
time={duration}
|
||||
delay={0}
|
||||
placeholder='Duration'
|
||||
previousEnd={previousEnd}
|
||||
warning={warning.duration}
|
||||
/>
|
||||
{delay !== 0 && delay !== null && (
|
||||
{delayTime && (
|
||||
<div className={style.delayNote}>
|
||||
{`${delayTime} minutes`}
|
||||
{delayTime}
|
||||
<br />
|
||||
{`New start: ${newTime}`}
|
||||
</div>
|
||||
|
||||
@@ -10,11 +10,7 @@ import {
|
||||
useSensor,
|
||||
useSensors,
|
||||
} from '@dnd-kit/core';
|
||||
import {
|
||||
horizontalListSortingStrategy,
|
||||
SortableContext,
|
||||
sortableKeyboardCoordinates,
|
||||
} from '@dnd-kit/sortable';
|
||||
import { horizontalListSortingStrategy, SortableContext, sortableKeyboardCoordinates } from '@dnd-kit/sortable';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { TableSettingsContext } from '../../common/context/TableSettingsContext';
|
||||
@@ -148,7 +144,7 @@ export default function OntimeTable({ tableData, userFields, selectedId, handleU
|
||||
if (el) {
|
||||
el.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start',
|
||||
block: 'center',
|
||||
inline: 'nearest',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
grid-area: schedule;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
margin-left: 16px;
|
||||
margin-left: clamp(16px, 5vw, 64px);;
|
||||
}
|
||||
|
||||
.schedule-nav-container {
|
||||
@@ -131,6 +131,8 @@
|
||||
grid-area: info;
|
||||
display: flex;
|
||||
gap: max(1vw, 16px);
|
||||
align-self: flex-end;
|
||||
overflow: hidden;
|
||||
|
||||
&__message {
|
||||
font-size: clamp(16px, 1.5vw, 24px);
|
||||
@@ -141,7 +143,7 @@
|
||||
}
|
||||
|
||||
.qr {
|
||||
margin-left: auto;
|
||||
margin-left: clamp(16px, 5vw, 64px);;
|
||||
padding: 4px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
@@ -99,7 +99,8 @@
|
||||
grid-area: info;
|
||||
display: flex;
|
||||
gap: max(1vw, 16px);
|
||||
min-height: max(calc(100vh / 15), 128px);
|
||||
align-self: flex-end;
|
||||
overflow: hidden;
|
||||
|
||||
&__message {
|
||||
font-size: clamp(16px, 1.5vw, 24px);
|
||||
@@ -110,7 +111,7 @@
|
||||
}
|
||||
|
||||
.qr {
|
||||
margin-left: auto;
|
||||
margin-left: clamp(16px, 5vw, 64px);;
|
||||
padding: 4px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user