mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-10 01:43:43 +00:00
refactor: style cleanups and migrations
fix: close modal with button refactor: small type improvements refactor: migrate time inputs refactor: migrate tooltips refactor: prevent component resizing
This commit is contained in:
committed by
Carlos Valente
parent
6facd6a666
commit
17a7d035bf
@@ -1,7 +1,7 @@
|
||||
.corner {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 2rem;
|
||||
position: fixed;
|
||||
top: 6rem;
|
||||
right: 4rem;
|
||||
z-index: $zindex-floating;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Fragment } from 'react';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
|
||||
import Tooltip from '../../../common/components/tooltip/Tooltip';
|
||||
import { isKeyEnter } from '../../../common/utils/keyEvent';
|
||||
import { cx } from '../../../common/utils/styleUtils';
|
||||
import { tooltipDelayFast } from '../../../ontimeConfig';
|
||||
import { SettingsOption, SettingsOptionId, useAppSettingsMenu } from '../useAppSettingsMenu';
|
||||
import useAppSettingsNavigation from '../useAppSettingsNavigation';
|
||||
|
||||
@@ -26,7 +25,7 @@ export default function PanelList({ selectedPanel, location }: PanelListProps) {
|
||||
const isSelected = selectedPanel === panel.id;
|
||||
if (panel.highlight) {
|
||||
return (
|
||||
<Tooltip key={panel.id} label={panel.highlight} openDelay={tooltipDelayFast} shouldWrapChildren>
|
||||
<Tooltip key={panel.id} text={panel.highlight} render={<span />}>
|
||||
<PanelListItem panel={panel} location={location} isSelected={isSelected} />
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
@@ -23,13 +23,13 @@ export default function FeaturePanel({ location }: PanelBaseProps) {
|
||||
<Panel.Section>
|
||||
<Panel.Card>
|
||||
<Panel.SubHeader>Share Ontime Link</Panel.SubHeader>
|
||||
<Panel.Divider />
|
||||
{!isOntimeCloud && (
|
||||
<>
|
||||
<Panel.Paragraph>Ontime is streaming on the following network interfaces</Panel.Paragraph>
|
||||
<InfoNif />
|
||||
</>
|
||||
)}
|
||||
<Panel.Divider />
|
||||
<GenerateLinkFormExport />
|
||||
</Panel.Card>
|
||||
</Panel.Section>
|
||||
|
||||
@@ -73,18 +73,12 @@ export default function GenerateLinkForm({ hostOptions, pathOptions, isLockedToV
|
||||
};
|
||||
|
||||
return (
|
||||
<Panel.Section as='form' onSubmit={handleSubmit(onSubmit)} onKeyDown={(event) => preventEscape(event)}>
|
||||
<form onSubmit={handleSubmit(onSubmit)} onKeyDown={(event) => preventEscape(event)}>
|
||||
{errors.root && <Panel.Error>{errors.root.message}</Panel.Error>}
|
||||
{!isLockedToView ? (
|
||||
<Info>
|
||||
<Panel.Paragraph>
|
||||
You can generate a link to share with your team or to use in automation (such as companion).
|
||||
</Panel.Paragraph>
|
||||
</Info>
|
||||
<Info>You can generate a link to share with your team or to use in automation (such as companion).</Info>
|
||||
) : (
|
||||
<Info>
|
||||
<Panel.Paragraph>You can generate a link to share with your team</Panel.Paragraph>
|
||||
</Info>
|
||||
<Info>You can generate a link to share with your team</Info>
|
||||
)}
|
||||
<Panel.ListGroup>
|
||||
<Panel.ListItem>
|
||||
@@ -136,6 +130,6 @@ export default function GenerateLinkForm({ hostOptions, pathOptions, isLockedToV
|
||||
</div>
|
||||
</Panel.ListItem>
|
||||
</Panel.ListGroup>
|
||||
</Panel.Section>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ import { postUrlPresets } from '../../../../common/api/urlPresets';
|
||||
import { maybeAxiosError } from '../../../../common/api/utils';
|
||||
import Button from '../../../../common/components/buttons/Button';
|
||||
import IconButton from '../../../../common/components/buttons/IconButton';
|
||||
import TooltipActionBtn from '../../../../common/components/buttons/TooltipActionBtn';
|
||||
import Info from '../../../../common/components/info/Info';
|
||||
import Input from '../../../../common/components/input/input/Input';
|
||||
import ExternalLink from '../../../../common/components/link/external-link/ExternalLink';
|
||||
import Tooltip from '../../../../common/components/tooltip/Tooltip';
|
||||
import useUrlPresets from '../../../../common/hooks-query/useUrlPresets';
|
||||
import { preventEscape } from '../../../../common/utils/keyEvent';
|
||||
import { handleLinks } from '../../../../common/utils/linkUtils';
|
||||
@@ -194,17 +194,15 @@ export default function UrlPresetsForm() {
|
||||
<Panel.Error>{maybeUrlError}</Panel.Error>
|
||||
</td>
|
||||
<Panel.InlineElements relation='inner' as='td'>
|
||||
<TooltipActionBtn
|
||||
size='sm'
|
||||
isDisabled={!canTest}
|
||||
clickHandler={(event) => handleLinks(preset.alias, event)}
|
||||
tooltip='Test preset'
|
||||
aria-label='Test preset'
|
||||
variant='ontime-ghosted'
|
||||
color='#e2e2e2' // $gray-200
|
||||
icon={<IoOpenOutline />}
|
||||
<Tooltip
|
||||
text='Test preset'
|
||||
render={<IconButton variant='ghosted-white' />}
|
||||
data-testid={`field__test_${index}`}
|
||||
/>
|
||||
onClick={(event) => handleLinks(preset.alias, event)}
|
||||
disabled={!canTest}
|
||||
>
|
||||
<IoOpenOutline />
|
||||
</Tooltip>
|
||||
<IconButton
|
||||
onClick={() => remove(index)}
|
||||
variant='ghosted-destructive'
|
||||
|
||||
+9
-5
@@ -1,12 +1,13 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useFieldArray, useForm } from 'react-hook-form';
|
||||
import { IoAdd, IoTrash } from 'react-icons/io5';
|
||||
import { Select, Tooltip } from '@chakra-ui/react';
|
||||
import { Select } from '@chakra-ui/react';
|
||||
import { ImportMap, isAlphanumericWithSpace } from 'ontime-utils';
|
||||
|
||||
import Button from '../../../../../../common/components/buttons/Button';
|
||||
import IconButton from '../../../../../../common/components/buttons/IconButton';
|
||||
import Input from '../../../../../../common/components/input/input/Input';
|
||||
import Tooltip from '../../../../../../common/components/tooltip/Tooltip';
|
||||
import * as Panel from '../../../../panel-utils/PanelUtils';
|
||||
import useGoogleSheet from '../useGoogleSheet';
|
||||
import { useSheetStore } from '../useSheetStore';
|
||||
@@ -97,10 +98,13 @@ export default function ImportMapForm(props: ImportMapFormProps) {
|
||||
Import options
|
||||
<Panel.InlineElements>
|
||||
{!isSpreadsheet && (
|
||||
<Tooltip label='Revoke the google authentication'>
|
||||
<Button onClick={handleRevoke} disabled={isLoading}>
|
||||
Revoke
|
||||
</Button>
|
||||
<Tooltip
|
||||
text='Revoke the google authentication'
|
||||
render={<Button />}
|
||||
onClick={handleRevoke}
|
||||
disabled={isLoading}
|
||||
>
|
||||
Revoke
|
||||
</Tooltip>
|
||||
)}
|
||||
<Button onClick={onCancel} disabled={isLoading}>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { IoArrowDown, IoArrowUp, IoBan, IoFlag, IoTime } from 'react-icons/io5';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { TimerPhase, TimerType } from 'ontime-types';
|
||||
|
||||
import { Corner } from '../../../common/components/editor-utils/EditorUtils';
|
||||
import Tooltip from '../../../common/components/tooltip/Tooltip';
|
||||
import { useMessagePreview } from '../../../common/hooks/useSocket';
|
||||
import useViewSettings from '../../../common/hooks-query/useViewSettings';
|
||||
import { handleLinks } from '../../../common/utils/linkUtils';
|
||||
import { cx, timerPlaceholder } from '../../../common/utils/styleUtils';
|
||||
import { tooltipDelayMid } from '../../../ontimeConfig';
|
||||
|
||||
import style from './MessageControl.module.scss';
|
||||
|
||||
@@ -64,20 +63,45 @@ export default function TimerPreview() {
|
||||
{secondary !== null && <div className={style.secondaryContent}>{secondary}</div>}
|
||||
</div>
|
||||
<div className={style.eventStatus}>
|
||||
<Tooltip label='Time type: Count down' openDelay={tooltipDelayMid} shouldWrapChildren>
|
||||
<IoArrowDown className={style.statusIcon} data-active={timerType === TimerType.CountDown} />
|
||||
<Tooltip
|
||||
text='Time type: Count down'
|
||||
render={<span />}
|
||||
className={style.statusIcon}
|
||||
data-active={timerType === TimerType.CountDown}
|
||||
>
|
||||
<IoArrowDown />
|
||||
</Tooltip>
|
||||
<Tooltip label='Time type: Count up' openDelay={tooltipDelayMid} shouldWrapChildren>
|
||||
<IoArrowUp className={style.statusIcon} data-active={timerType === TimerType.CountUp} />
|
||||
<Tooltip
|
||||
text='Time type: Count up'
|
||||
render={<span />}
|
||||
className={style.statusIcon}
|
||||
data-active={timerType === TimerType.CountUp}
|
||||
>
|
||||
<IoArrowUp />
|
||||
</Tooltip>
|
||||
<Tooltip label='Time type: Clock' openDelay={tooltipDelayMid} shouldWrapChildren>
|
||||
<IoTime className={style.statusIcon} data-active={timerType === TimerType.Clock} />
|
||||
<Tooltip
|
||||
text='Time type: Clock'
|
||||
render={<span />}
|
||||
className={style.statusIcon}
|
||||
data-active={timerType === TimerType.Clock}
|
||||
>
|
||||
<IoTime />
|
||||
</Tooltip>
|
||||
<Tooltip label='Time type: None' openDelay={tooltipDelayMid} shouldWrapChildren>
|
||||
<IoBan className={style.statusIcon} data-active={timerType === TimerType.None} />
|
||||
<Tooltip
|
||||
text='Time type: None'
|
||||
render={<span />}
|
||||
className={style.statusIcon}
|
||||
data-active={timerType === TimerType.None}
|
||||
>
|
||||
<IoBan />
|
||||
</Tooltip>
|
||||
<Tooltip label={countToEnd ? 'Count to end' : 'Count duration'} openDelay={tooltipDelayMid} shouldWrapChildren>
|
||||
<IoFlag className={style.statusIcon} data-active={countToEnd} />
|
||||
<Tooltip
|
||||
text={countToEnd ? 'Count to end' : 'Count duration'}
|
||||
render={<span />}
|
||||
className={style.statusIcon}
|
||||
data-active={countToEnd}
|
||||
>
|
||||
<IoFlag />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
}
|
||||
|
||||
.auxTimers {
|
||||
display: flex;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { IoAdd, IoRemove } from 'react-icons/io5';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { useLocalStorage } from '@mantine/hooks';
|
||||
import { Playback } from 'ontime-types';
|
||||
import { MILLIS_PER_HOUR, parseUserTime } from 'ontime-utils';
|
||||
|
||||
import TimeInput from '../../../../common/components/input/time-input/TimeInput';
|
||||
import { setPlayback } from '../../../../common/hooks/useSocket';
|
||||
import { tooltipDelayMid } from '../../../../ontimeConfig';
|
||||
import TapButton from '../tap-button/TapButton';
|
||||
|
||||
import style from './AddTime.module.scss';
|
||||
@@ -41,16 +39,12 @@ export default function AddTime(props: AddTimeProps) {
|
||||
<div className={style.addTime}>
|
||||
<TimeInput name='addtime' submitHandler={handleTimeChange} time={timeInMs} placeholder='Add time' />
|
||||
<div className={style.addButtons}>
|
||||
<Tooltip label='Remove time' openDelay={tooltipDelayMid} shouldWrapChildren>
|
||||
<TapButton onClick={() => handleAddTime('remove')} disabled={doDisableButtons} className={style.tallButtons}>
|
||||
<IoRemove />
|
||||
</TapButton>
|
||||
</Tooltip>
|
||||
<Tooltip label='Add time' openDelay={tooltipDelayMid} shouldWrapChildren>
|
||||
<TapButton onClick={() => handleAddTime('add')} disabled={doDisableButtons} className={style.tallButtons}>
|
||||
<IoAdd />
|
||||
</TapButton>
|
||||
</Tooltip>
|
||||
<TapButton onClick={() => handleAddTime('remove')} disabled={doDisableButtons} className={style.tallButtons}>
|
||||
<IoRemove />
|
||||
</TapButton>
|
||||
<TapButton onClick={() => handleAddTime('add')} disabled={doDisableButtons} className={style.tallButtons}>
|
||||
<IoAdd />
|
||||
</TapButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -22,3 +22,24 @@
|
||||
gap: 0.25rem;
|
||||
height: 1.5rem;
|
||||
}
|
||||
|
||||
.fakeInput {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
max-width: 7.5em;
|
||||
height: 2rem;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
color: $gray-200;
|
||||
border-radius: $component-border-radius-md;
|
||||
border: 1px solid transparent;
|
||||
letter-spacing: 0.5px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
|
||||
padding-inline: 0.5em;
|
||||
outline: none;
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { IoArrowDown, IoArrowUp, IoPause, IoPlay, IoStop } from 'react-icons/io5';
|
||||
import { Playback, SimpleDirection, SimplePlayback } from 'ontime-types';
|
||||
import { parseUserTime } from 'ontime-utils';
|
||||
import { millisToString, parseUserTime } from 'ontime-utils';
|
||||
|
||||
import TimeInput from '../../../../common/components/input/time-input/TimeInput';
|
||||
import { setAuxTimer, useAuxTimerControl, useAuxTimerTime } from '../../../../common/hooks/useSocket';
|
||||
@@ -22,7 +22,7 @@ export function AuxTimer({ index }: AuxTimerProps) {
|
||||
setDirection(index, newDirection);
|
||||
};
|
||||
|
||||
const canStop = playback !== SimplePlayback.Stop;
|
||||
const isActive = playback !== SimplePlayback.Stop;
|
||||
const playbackAction = playback === SimplePlayback.Start ? 'pause' : 'play';
|
||||
|
||||
return (
|
||||
@@ -30,15 +30,15 @@ export function AuxTimer({ index }: AuxTimerProps) {
|
||||
Aux Timer {index}
|
||||
<div className={style.controls}>
|
||||
<div className={style.input}>
|
||||
<AuxTimerInput index={index} />
|
||||
<TapButton onClick={toggleDirection} aspect='tight'>
|
||||
<AuxTimerInput index={index} isActive={isActive} />
|
||||
<TapButton onClick={toggleDirection} aspect='tight' disabled={isActive}>
|
||||
{direction === SimpleDirection.CountDown && <IoArrowDown data-testid={`aux-timer-direction-${index}`} />}
|
||||
{direction === SimpleDirection.CountUp && <IoArrowUp data-testid={`aux-timer-direction-${index}`} />}
|
||||
</TapButton>
|
||||
</div>
|
||||
<div className={style.twoSides}>
|
||||
<AuxTogglePlay index={index} action={playbackAction} />
|
||||
<TapButton onClick={() => stop(index)} theme={Playback.Stop} disabled={!canStop}>
|
||||
<TapButton onClick={() => stop(index)} theme={Playback.Stop} disabled={!isActive}>
|
||||
<IoStop data-testid={`aux-timer-stop-${index}`} />
|
||||
</TapButton>
|
||||
</div>
|
||||
@@ -47,11 +47,12 @@ export function AuxTimer({ index }: AuxTimerProps) {
|
||||
);
|
||||
}
|
||||
|
||||
interface AuxTimerInput {
|
||||
interface AuxTimerInputProps {
|
||||
index: number;
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
function AuxTimerInput({ index }: AuxTimerProps) {
|
||||
function AuxTimerInput({ index, isActive }: AuxTimerInputProps) {
|
||||
const newTimeInMs = useAuxTimerTime(index);
|
||||
const { setDuration } = setAuxTimer;
|
||||
|
||||
@@ -60,6 +61,14 @@ function AuxTimerInput({ index }: AuxTimerProps) {
|
||||
setDuration(index, newTimeInMs);
|
||||
};
|
||||
|
||||
if (isActive) {
|
||||
return (
|
||||
<div className={style.fakeInput} data-testid={`time-label-aux${index}`}>
|
||||
{millisToString(newTimeInMs)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TimeInput submitHandler={handleTimeUpdate} name={`aux${index}`} time={newTimeInMs} placeholder={`Aux ${index}`} />
|
||||
);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { useMemo } from 'react';
|
||||
import { IoPause, IoPlay, IoPlaySkipBack, IoPlaySkipForward, IoReload, IoStop, IoTime } from 'react-icons/io5';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { Playback, TimerPhase } from 'ontime-types';
|
||||
import { validatePlayback } from 'ontime-utils';
|
||||
|
||||
import { setPlayback } from '../../../../common/hooks/useSocket';
|
||||
import { tooltipDelayMid } from '../../../../ontimeConfig';
|
||||
import TapButton from '../tap-button/TapButton';
|
||||
|
||||
import style from './PlaybackButtons.module.scss';
|
||||
@@ -66,31 +64,23 @@ export default function PlaybackButtons(props: PlaybackButtonsProps) {
|
||||
</TapButton>
|
||||
</div>
|
||||
<div className={style.transportContainer}>
|
||||
<Tooltip label='Previous event' openDelay={tooltipDelayMid}>
|
||||
<TapButton onClick={setPlayback.previous} disabled={disablePrev}>
|
||||
<IoPlaySkipBack />
|
||||
</TapButton>
|
||||
</Tooltip>
|
||||
<Tooltip label='Next event' openDelay={tooltipDelayMid}>
|
||||
<TapButton onClick={setPlayback.next} disabled={disableNext}>
|
||||
<IoPlaySkipForward />
|
||||
</TapButton>
|
||||
</Tooltip>
|
||||
<TapButton onClick={setPlayback.previous} disabled={disablePrev}>
|
||||
<IoPlaySkipBack />
|
||||
</TapButton>
|
||||
<TapButton onClick={setPlayback.next} disabled={disableNext}>
|
||||
<IoPlaySkipForward />
|
||||
</TapButton>
|
||||
</div>
|
||||
<div className={style.extra}>
|
||||
<TapButton onClick={setPlayback.roll} disabled={disableRoll} theme={Playback.Roll} active={isRolling}>
|
||||
<IoTime />
|
||||
</TapButton>
|
||||
<Tooltip label='Reload event' openDelay={tooltipDelayMid}>
|
||||
<TapButton onClick={setPlayback.reload} disabled={disableReload}>
|
||||
<IoReload className={style.invertX} />
|
||||
</TapButton>
|
||||
</Tooltip>
|
||||
<Tooltip label='Unload Event' openDelay={tooltipDelayMid}>
|
||||
<TapButton onClick={setPlayback.stop} disabled={disableStop} theme={Playback.Stop}>
|
||||
<IoStop />
|
||||
</TapButton>
|
||||
</Tooltip>
|
||||
<TapButton onClick={setPlayback.reload} disabled={disableReload}>
|
||||
<IoReload className={style.invertX} />
|
||||
</TapButton>
|
||||
<TapButton onClick={setPlayback.stop} disabled={disableStop} theme={Playback.Stop}>
|
||||
<IoStop />
|
||||
</TapButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { PropsWithChildren } from 'react';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { MaybeNumber, Playback, TimerPhase } from 'ontime-types';
|
||||
import { dayInMs, millisToString } from 'ontime-utils';
|
||||
|
||||
import AppLink from '../../../../common/components/link/app-link/AppLink';
|
||||
import Tooltip from '../../../../common/components/tooltip/Tooltip';
|
||||
import { useTimer } from '../../../../common/hooks/useSocket';
|
||||
import useReport from '../../../../common/hooks-query/useReport';
|
||||
import { formatDuration } from '../../../../common/utils/time';
|
||||
@@ -43,13 +43,9 @@ export default function PlaybackTimer(props: PropsWithChildren<PlaybackTimerProp
|
||||
return (
|
||||
<div className={style.timeContainer}>
|
||||
<div className={style.indicators}>
|
||||
<Tooltip label={rollLabel}>
|
||||
<div className={style.indicatorRoll} data-active={isRolling} />
|
||||
</Tooltip>
|
||||
<Tooltip text={rollLabel} render={<div />} className={style.indicatorRoll} data-active={isRolling} />
|
||||
<div className={style.indicatorNegative} data-active={isOvertime} />
|
||||
<Tooltip label={addedTimeLabel}>
|
||||
<div className={style.indicatorDelay} data-active={hasAddedTime} />
|
||||
</Tooltip>
|
||||
<Tooltip text={addedTimeLabel} render={<div />} className={style.indicatorDelay} data-active={hasAddedTime} />
|
||||
</div>
|
||||
<TimerDisplay time={isWaiting ? timer.secondaryTimer : timer.current} />
|
||||
<div className={style.status}>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
|
||||
import Tooltip from '../../../common/components/tooltip/Tooltip';
|
||||
import { cx } from '../../../common/utils/styleUtils';
|
||||
|
||||
import style from './TimeLayout.module.scss';
|
||||
@@ -29,8 +28,12 @@ export function TimeRow({ label, value, daySpan, muted, className }: TimeLayoutP
|
||||
<div className={style.row}>
|
||||
<span className={style.label}>{label}</span>
|
||||
{daySpan ? (
|
||||
<Tooltip label={`Event spans over ${daySpan + 1} days`}>
|
||||
<span className={cx([style.clock, style.daySpan, className])}>{value}</span>
|
||||
<Tooltip
|
||||
text={`Event spans over ${daySpan + 1} days`}
|
||||
render={<span />}
|
||||
className={cx([style.clock, style.daySpan, className])}
|
||||
>
|
||||
{value}
|
||||
</Tooltip>
|
||||
) : (
|
||||
<span className={cx([style.clock, muted && style.muted, className])}>{value}</span>
|
||||
|
||||
@@ -22,6 +22,7 @@ $block-cursor-color: $orange-400;
|
||||
border-radius: $block-border-radius;
|
||||
position: relative;
|
||||
color: $block-text-color;
|
||||
overflow: hidden;
|
||||
|
||||
min-width: $block-width;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { memo } from 'react';
|
||||
import { IoInformationCircle } from 'react-icons/io5';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { EndAction, TimerType, TimeStrategy } from 'ontime-types';
|
||||
import { millisToString, parseUserTime } from 'ontime-utils';
|
||||
|
||||
@@ -8,6 +7,7 @@ import * as Editor from '../../../../common/components/editor-utils/EditorUtils'
|
||||
import TimeInput from '../../../../common/components/input/time-input/TimeInput';
|
||||
import Select from '../../../../common/components/select/Select';
|
||||
import Switch from '../../../../common/components/switch/Switch';
|
||||
import Tooltip from '../../../../common/components/tooltip/Tooltip';
|
||||
import { useEntryActions } from '../../../../common/hooks/useEntryAction';
|
||||
import { millisToDelayString } from '../../../../common/utils/dateConfig';
|
||||
import TimeInputFlow from '../../time-input-flow/TimeInputFlow';
|
||||
@@ -126,11 +126,12 @@ function EventEditorTimes({
|
||||
|
||||
<div className={style.column}>
|
||||
<Editor.Title>
|
||||
<Tooltip label='Changes how the timer is displayed in different views. It is not reflected in the rundown'>
|
||||
<span>
|
||||
Display Options
|
||||
<IoInformationCircle className={style.tooltipIcon} />
|
||||
</span>
|
||||
<Tooltip
|
||||
text='Changes how the timer is displayed in different views. It is not reflected in the rundown'
|
||||
render={<span />}
|
||||
>
|
||||
Display Options
|
||||
<IoInformationCircle className={style.tooltipIcon} />
|
||||
</Tooltip>
|
||||
</Editor.Title>
|
||||
<div className={style.splitTwo}>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Fragment, useCallback, useMemo, useState } from 'react';
|
||||
import { IoAlertCircle, IoCheckmarkCircle, IoTrash } from 'react-icons/io5';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { TimerLifeCycle, timerLifecycleValues, Trigger } from 'ontime-types';
|
||||
import { generateId } from 'ontime-utils';
|
||||
|
||||
@@ -8,6 +7,7 @@ import Button from '../../../../common/components/buttons/Button';
|
||||
import IconButton from '../../../../common/components/buttons/IconButton';
|
||||
import Select from '../../../../common/components/select/Select';
|
||||
import Tag from '../../../../common/components/tag/Tag';
|
||||
import Tooltip from '../../../../common/components/tooltip/Tooltip';
|
||||
import { useEntryActions } from '../../../../common/hooks/useEntryAction';
|
||||
import useAutomationSettings from '../../../../common/hooks-query/useAutomationSettings';
|
||||
|
||||
@@ -107,7 +107,7 @@ function EventTriggerForm({ eventId, triggers }: EventTriggerFormProps) {
|
||||
Add
|
||||
</Button>
|
||||
{validationError !== undefined ? (
|
||||
<Tooltip label={validationError} shouldWrapChildren>
|
||||
<Tooltip text={validationError} render={<span />}>
|
||||
<IoAlertCircle className={style.errorLabel} />
|
||||
</Tooltip>
|
||||
) : (
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
|
||||
.block {
|
||||
@include block-styling;
|
||||
overflow: hidden;
|
||||
|
||||
margin-block: 1rem 0.25rem;
|
||||
display: grid;
|
||||
grid-template-columns: 2rem 1fr;
|
||||
grid-template-areas: 'binder header';
|
||||
align-items: center;
|
||||
// TODO(style fix): groups have an extra bottom margin which interrupt colour
|
||||
margin-block: 0.25rem;
|
||||
|
||||
&.hasCursor {
|
||||
outline: 1px solid $block-cursor-color;
|
||||
}
|
||||
|
||||
&.expanded {
|
||||
margin-block: 1rem 0;
|
||||
border-radius: $block-border-radius $block-border-radius 0 0;
|
||||
border-bottom: 0.25rem solid color-mix(in srgb, transparent 90%, var(--user-bg, transparent) 10%);
|
||||
}
|
||||
|
||||
.binder {
|
||||
@@ -29,8 +29,12 @@
|
||||
place-content: center;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: 1px solid $blue-500;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
grid-area: header;
|
||||
|
||||
@@ -102,8 +102,9 @@ export default function RundownBlock({ data, hasCursor, collapsed, onCollapse }:
|
||||
onClick={handleFocusClick}
|
||||
onContextMenu={onContextMenu}
|
||||
style={{
|
||||
...(binderColours ? { '--user-bg': binderColours.backgroundColor } : {}),
|
||||
// ...(binderColours ? { '--user-bg': binderColours.backgroundColor } : {}),
|
||||
...dragStyle,
|
||||
'--user-bg': data.colour || '#929292',
|
||||
}}
|
||||
data-testid='rundown-block'
|
||||
>
|
||||
|
||||
@@ -4,12 +4,11 @@
|
||||
@include block-styling;
|
||||
|
||||
margin-block: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
background-color: $block-bg2;
|
||||
padding-right: 0.5rem;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 2rem 1fr auto;
|
||||
grid-template-areas: 'drag inpt btns';
|
||||
grid-template-columns: 2rem 1fr auto auto;
|
||||
align-items: center;
|
||||
height: $secondary-block-height;
|
||||
gap: 0.5rem;
|
||||
@@ -21,12 +20,4 @@
|
||||
|
||||
.drag {
|
||||
@include drag-style;
|
||||
grid-area: drag;
|
||||
}
|
||||
|
||||
.actionButtons {
|
||||
grid-area: btns;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
@@ -55,23 +55,24 @@ export default function RundownDelay({ data, hasCursor }: RundownDelayProps) {
|
||||
deleteEntry([data.id]);
|
||||
};
|
||||
|
||||
const blockClasses = cx([style.delay, hasCursor ? style.hasCursor : null]);
|
||||
|
||||
return (
|
||||
<div className={blockClasses} ref={setNodeRef} style={dragStyle} data-testid='rundown-delay'>
|
||||
<div
|
||||
className={cx([style.delay, hasCursor ? style.hasCursor : null])}
|
||||
ref={setNodeRef}
|
||||
style={dragStyle}
|
||||
data-testid='rundown-delay'
|
||||
>
|
||||
<span className={style.drag} ref={handleRef} {...dragAttributes} {...dragListeners}>
|
||||
<IoReorderTwo />
|
||||
</span>
|
||||
<DelayInput eventId={data.id} duration={data.duration} />
|
||||
<div className={style.actionButtons}>
|
||||
<Button onClick={applyDelayHandler} variant='ghosted-white'>
|
||||
<IoCheckmarkDone /> Make permanent
|
||||
</Button>
|
||||
<Button onClick={cancelDelayHandler} variant='ghosted-white'>
|
||||
<IoClose />
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
<Button onClick={applyDelayHandler} variant='ghosted-white'>
|
||||
<IoCheckmarkDone /> Make permanent
|
||||
</Button>
|
||||
<Button onClick={cancelDelayHandler} variant='ghosted-white'>
|
||||
<IoClose />
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ $skip-opacity: 0.2;
|
||||
@include block-styling;
|
||||
background-color: $block-bg;
|
||||
margin-block: 0.25rem;
|
||||
overflow: initial;
|
||||
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
@@ -15,7 +16,7 @@ $skip-opacity: 0.2;
|
||||
'binder pb-actions estatus estatus'
|
||||
'binder ... ... ...';
|
||||
|
||||
grid-template-columns: $block-binder-width 3rem 1fr auto;
|
||||
grid-template-columns: $block-binder-width 3rem 1fr 3rem;
|
||||
grid-template-rows: 0.125rem 2rem 2rem auto 0.125rem;
|
||||
align-items: center;
|
||||
padding-right: $block-clearance;
|
||||
@@ -92,11 +93,10 @@ $skip-opacity: 0.2;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
border-radius: $block-border-radius 0 0 $block-border-radius;
|
||||
|
||||
background-color: $gray-1050; // to override inline
|
||||
color: $section-white;
|
||||
font-size: 1rem;
|
||||
border-radius: 3px 0 0 3px;
|
||||
|
||||
.drag {
|
||||
@include drag-style;
|
||||
|
||||
@@ -10,11 +10,10 @@ import {
|
||||
IoPlaySkipForward,
|
||||
IoTime,
|
||||
} from 'react-icons/io5';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { EndAction, Playback, TimerType, TimeStrategy } from 'ontime-types';
|
||||
|
||||
import Tooltip from '../../../common/components/tooltip/Tooltip';
|
||||
import { cx } from '../../../common/utils/styleUtils';
|
||||
import { tooltipDelayMid } from '../../../ontimeConfig';
|
||||
import EditableBlockTitle from '../common/EditableBlockTitle';
|
||||
import TimeInputFlow from '../time-input-flow/TimeInputFlow';
|
||||
|
||||
@@ -137,25 +136,17 @@ function RundownEventInner({
|
||||
{loaded && <EventBlockProgressBar />}
|
||||
</div>
|
||||
<div className={style.eventStatus} tabIndex={-1}>
|
||||
<Tooltip label={`Time type: ${timerType}`} openDelay={tooltipDelayMid}>
|
||||
<span>
|
||||
<TimerIcon type={timerType} className={style.statusIcon} />
|
||||
</span>
|
||||
<Tooltip text={`Time type: ${timerType}`} render={<span />}>
|
||||
<TimerIcon type={timerType} className={style.statusIcon} />
|
||||
</Tooltip>
|
||||
<Tooltip label={`End action: ${endAction}`} openDelay={tooltipDelayMid}>
|
||||
<span>
|
||||
<EndActionIcon action={endAction} className={style.statusIcon} />
|
||||
</span>
|
||||
<Tooltip text={`End action: ${endAction}`} render={<span />}>
|
||||
<EndActionIcon action={endAction} className={style.statusIcon} />
|
||||
</Tooltip>
|
||||
<Tooltip label={`${countToEnd ? 'Count to End' : 'Count duration'}`} openDelay={tooltipDelayMid}>
|
||||
<span>
|
||||
<IoFlag className={`${style.statusIcon} ${countToEnd ? style.active : style.disabled}`} />
|
||||
</span>
|
||||
<Tooltip text={`${countToEnd ? 'Count to End' : 'Count duration'}`} render={<span />}>
|
||||
<IoFlag className={`${style.statusIcon} ${countToEnd ? style.active : style.disabled}`} />
|
||||
</Tooltip>
|
||||
<Tooltip label='Event has Triggers' openDelay={tooltipDelayMid}>
|
||||
<span>
|
||||
<IoFlash className={`${style.statusIcon} ${hasTriggers ? style.active : style.disabled}`} />
|
||||
</span>
|
||||
<Tooltip text='Event has Triggers' render={<span />}>
|
||||
<IoFlash className={`${style.statusIcon} ${hasTriggers ? style.active : style.disabled}`} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ $gap-left: calc(2rem + 0.25rem + 3rem);
|
||||
font-size: calc(1rem - 5px);
|
||||
position: absolute;
|
||||
top: -1em;
|
||||
z-index: $zindex-floating;;
|
||||
z-index: $zindex-floating;
|
||||
margin-left: $gap-left;
|
||||
|
||||
display: flex;
|
||||
|
||||
+1
-3
@@ -1,11 +1,9 @@
|
||||
.chip {
|
||||
background-color: $gray-1100;
|
||||
white-space: nowrap;
|
||||
|
||||
font-size: calc(1rem - 3px);
|
||||
color: $label-gray;
|
||||
padding: 0.125rem 0.5rem;
|
||||
border-radius: 2px;
|
||||
justify-self: end;
|
||||
|
||||
&.over {
|
||||
color: $ontime-delay-text;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { useMemo } from 'react';
|
||||
import { IoCheckmarkCircle } from 'react-icons/io5';
|
||||
import { Tooltip } from '@chakra-ui/react';
|
||||
import { isPlaybackActive, MILLIS_PER_MINUTE, MILLIS_PER_SECOND } from 'ontime-utils';
|
||||
|
||||
import Tooltip from '../../../../common/components/tooltip/Tooltip';
|
||||
import { usePlayback } from '../../../../common/hooks/useSocket';
|
||||
import useReport from '../../../../common/hooks-query/useReport';
|
||||
import { cx } from '../../../../common/utils/styleUtils';
|
||||
import { formatDuration, formatTime, useTimeUntilStart } from '../../../../common/utils/time';
|
||||
import { tooltipDelayFast } from '../../../../ontimeConfig';
|
||||
|
||||
import style from './RundownEventChip.module.scss';
|
||||
|
||||
@@ -39,7 +38,7 @@ export default function RundownEventChip({
|
||||
const { playback } = usePlayback();
|
||||
|
||||
if (isLoaded) {
|
||||
return null; //TODO: the is a small flash of 'DUE' on the loaded event as clock data arrives before isLoaded propagates
|
||||
return null;
|
||||
}
|
||||
|
||||
const playbackActive = isPlaybackActive(playback);
|
||||
@@ -51,16 +50,14 @@ export default function RundownEventChip({
|
||||
if (playbackActive) {
|
||||
// we extracted the component to avoid unnecessary calculations and re-renders
|
||||
return (
|
||||
<Tooltip label='Expected time until start' openDelay={tooltipDelayFast}>
|
||||
<div className={className}>
|
||||
<EventUntil
|
||||
timeStart={timeStart}
|
||||
delay={delay}
|
||||
dayOffset={dayOffset}
|
||||
totalGap={totalGap}
|
||||
isLinkedToLoaded={isLinkedToLoaded}
|
||||
/>
|
||||
</div>
|
||||
<Tooltip text='Expected time until start' render={<span />} className={className}>
|
||||
<EventUntil
|
||||
timeStart={timeStart}
|
||||
delay={delay}
|
||||
dayOffset={dayOffset}
|
||||
totalGap={totalGap}
|
||||
isLinkedToLoaded={isLinkedToLoaded}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
@@ -113,7 +110,7 @@ function EventReport(props: EventReportProps) {
|
||||
const absDifference = Math.abs(difference);
|
||||
|
||||
if (absDifference < MILLIS_PER_SECOND) {
|
||||
return ['ontime', 'ontime', 'Event finished ontime'];
|
||||
return ['ontime', 'under', 'Event finished on time'];
|
||||
}
|
||||
|
||||
const isOver = difference > 0;
|
||||
@@ -131,10 +128,8 @@ function EventReport(props: EventReportProps) {
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip label={tooltip} openDelay={tooltipDelayFast}>
|
||||
<div className={cx([style.chip, style[overUnderStyle], className])}>
|
||||
{value === 'ontime' ? <IoCheckmarkCircle size='1.1rem' /> : value}
|
||||
</div>
|
||||
<Tooltip text={tooltip} render={<span />} className={cx([style.chip, style[overUnderStyle], className])}>
|
||||
{value === 'ontime' ? <IoCheckmarkCircle size='1.1rem' /> : value}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,28 +1,13 @@
|
||||
import { memo, MouseEvent } from 'react';
|
||||
import { IoPause, IoPlay, IoReload, IoRemoveCircle, IoRemoveCircleOutline } from 'react-icons/io5';
|
||||
|
||||
import TooltipActionBtn from '../../../../common/components/buttons/TooltipActionBtn';
|
||||
import IconButton from '../../../../common/components/buttons/IconButton';
|
||||
import Tooltip from '../../../../common/components/tooltip/Tooltip';
|
||||
import { useEntryActions } from '../../../../common/hooks/useEntryAction';
|
||||
import { setEventPlayback } from '../../../../common/hooks/useSocket';
|
||||
import { tooltipDelayMid } from '../../../../ontimeConfig';
|
||||
|
||||
import style from '../RundownEvent.module.scss';
|
||||
|
||||
const blockBtnStyle = {
|
||||
size: 'sm',
|
||||
};
|
||||
|
||||
type StyleVariant = {
|
||||
'aria-label': string;
|
||||
tooltip: string;
|
||||
backgroundColor: string;
|
||||
_hover: { backgroundColor?: string };
|
||||
};
|
||||
|
||||
const tooltipProps = {
|
||||
openDelay: tooltipDelayMid,
|
||||
};
|
||||
|
||||
interface RundownEventPlaybackProps {
|
||||
eventId: string;
|
||||
skip: boolean;
|
||||
@@ -67,67 +52,66 @@ function RundownEventPlayback({
|
||||
setEventPlayback.loadEvent(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' };
|
||||
const playButtonStyles: { tooltip: string; backgroundColor: string | undefined } = (() => {
|
||||
if (isPaused) {
|
||||
return {
|
||||
tooltip: 'Continue event',
|
||||
backgroundColor: '#339E4E',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (isPlaying) {
|
||||
return {
|
||||
tooltip: 'Pause event',
|
||||
backgroundColor: '#c05621',
|
||||
};
|
||||
}
|
||||
return {
|
||||
tooltip: 'Start event',
|
||||
backgroundColor: undefined,
|
||||
};
|
||||
})();
|
||||
|
||||
return (
|
||||
<div className={style.playbackActions}>
|
||||
<TooltipActionBtn
|
||||
variant='ontime-subtle-white'
|
||||
<Tooltip
|
||||
text='Skip event'
|
||||
render={<IconButton variant='subtle-white' />}
|
||||
onClick={toggleSkip}
|
||||
tabIndex={-1}
|
||||
disabled={loaded}
|
||||
style={{
|
||||
background: skip ? '#9A0000' : undefined,
|
||||
}}
|
||||
aria-label='Skip event'
|
||||
tooltip='Skip event'
|
||||
icon={skip ? <IoRemoveCircle /> : <IoRemoveCircleOutline />}
|
||||
backgroundColor={skip ? '#B20000' : undefined}
|
||||
_hover={{ backgroundColor: '#FF7878' }}
|
||||
{...tooltipProps}
|
||||
{...blockBtnStyle}
|
||||
clickHandler={toggleSkip}
|
||||
>
|
||||
{skip ? <IoRemoveCircle /> : <IoRemoveCircleOutline />}
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip
|
||||
text='Load event'
|
||||
render={<IconButton variant='subtle-white' />}
|
||||
onClick={load}
|
||||
tabIndex={-1}
|
||||
isDisabled={loaded}
|
||||
/>
|
||||
<TooltipActionBtn
|
||||
variant='ontime-subtle-white'
|
||||
disabled={disablePlayback}
|
||||
aria-label='Load event'
|
||||
tooltip='Load event'
|
||||
icon={<IoReload className={style.flip} />}
|
||||
isDisabled={disablePlayback}
|
||||
{...tooltipProps}
|
||||
{...blockBtnStyle}
|
||||
clickHandler={load}
|
||||
>
|
||||
<IoReload className={style.flip} />
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip
|
||||
text={playButtonStyles.tooltip}
|
||||
render={<IconButton variant='subtle-white' />}
|
||||
onClick={actionHandler}
|
||||
tabIndex={-1}
|
||||
/>
|
||||
<TooltipActionBtn
|
||||
variant='ontime-subtle-white'
|
||||
aria-label='Start event'
|
||||
tooltip='Start event'
|
||||
icon={!isPlaying ? <IoPlay /> : <IoPause />}
|
||||
isDisabled={disablePlayback}
|
||||
{...tooltipProps}
|
||||
{...blockBtnStyle}
|
||||
{...buttonVariant}
|
||||
clickHandler={actionHandler}
|
||||
tabIndex={-1}
|
||||
/>
|
||||
disabled={disablePlayback}
|
||||
style={{
|
||||
backgroundColor: playButtonStyles.backgroundColor,
|
||||
}}
|
||||
aria-label={isPlaying ? 'Pause event' : 'Start event'}
|
||||
>
|
||||
{!isPlaying ? <IoPlay /> : <IoPause />}
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,30 +1,63 @@
|
||||
.timeLabel {
|
||||
position: absolute;
|
||||
z-index: $zindex-floating;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
top: 2px;
|
||||
right: 4px;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.timeAction {
|
||||
opacity: 0.4;
|
||||
background: $gray-1050;
|
||||
color: $gray-500;
|
||||
cursor: pointer;
|
||||
padding-right: 0.5em;
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
aspect-ratio: 1;
|
||||
|
||||
&:hover:not(:disabled):not(:active) {
|
||||
background: $gray-1000;
|
||||
}
|
||||
|
||||
&:active:not(:disabled) {
|
||||
background: $gray-1300;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: 1px solid $blue-500;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
&.active {
|
||||
opacity: 1;
|
||||
color: var(--status-color-active-override, $active-indicator);
|
||||
}
|
||||
.fourtyfive {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
|
||||
.fourtyfive {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.timerNote {
|
||||
width: 1.25em;
|
||||
color: $blue-500;
|
||||
margin-right: 0.5rem;
|
||||
font-size: 1.5em;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.inputGroup {
|
||||
border: 1px solid transparent;
|
||||
width: fit-content;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: $component-border-radius-md;
|
||||
|
||||
&.delayed {
|
||||
border: 1px solid $ontime-delay-text;
|
||||
}
|
||||
|
||||
input {
|
||||
max-width: 6.5em;
|
||||
border-radius: $component-border-radius-md 0 0 $component-border-radius-md;
|
||||
border: none;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 1.5rem;
|
||||
height: 2rem;
|
||||
border-radius: 0 $component-border-radius-md $component-border-radius-md 0;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { memo } from 'react';
|
||||
import { IoAlertCircleOutline, IoLink, IoLockClosed, IoLockOpenOutline, IoUnlink } from 'react-icons/io5';
|
||||
import { InputRightElement, Tooltip } from '@chakra-ui/react';
|
||||
import { TimeField, TimeStrategy } from 'ontime-types';
|
||||
import { dayInMs } from 'ontime-utils';
|
||||
|
||||
import * as Editor from '../../../common/components/editor-utils/EditorUtils';
|
||||
import TimeInputWithButton from '../../../common/components/input/time-input/TimeInputWithButton';
|
||||
import TimeInput from '../../../common/components/input/time-input/TimeInput';
|
||||
import Tooltip from '../../../common/components/tooltip/Tooltip';
|
||||
import { useEntryActions } from '../../../common/hooks/useEntryAction';
|
||||
import { cx } from '../../../common/utils/styleUtils';
|
||||
import { tooltipDelayFast, tooltipDelayMid } from '../../../ontimeConfig';
|
||||
|
||||
import style from './TimeInputFlow.module.scss';
|
||||
|
||||
@@ -25,8 +24,17 @@ interface EventBlockTimerProps {
|
||||
}
|
||||
|
||||
export default memo(TimeInputFlow);
|
||||
function TimeInputFlow(props: EventBlockTimerProps) {
|
||||
const { eventId, countToEnd, timeStart, timeEnd, duration, timeStrategy, linkStart, delay, showLabels } = props;
|
||||
function TimeInputFlow({
|
||||
eventId,
|
||||
countToEnd,
|
||||
timeStart,
|
||||
timeEnd,
|
||||
duration,
|
||||
timeStrategy,
|
||||
linkStart,
|
||||
delay,
|
||||
showLabels,
|
||||
}: EventBlockTimerProps) {
|
||||
const { updateEntry, updateTimer } = useEntryActions();
|
||||
|
||||
// In sync with EventEditorTimes
|
||||
@@ -52,86 +60,80 @@ function TimeInputFlow(props: EventBlockTimerProps) {
|
||||
}
|
||||
|
||||
const hasDelay = delay !== 0;
|
||||
|
||||
const isLockedEnd = timeStrategy === TimeStrategy.LockEnd;
|
||||
const isLockedDuration = timeStrategy === TimeStrategy.LockDuration;
|
||||
|
||||
const activeStart = cx([style.timeAction, linkStart && style.active]);
|
||||
const activeEnd = cx([style.timeAction, isLockedEnd && style.active]);
|
||||
const activeDuration = cx([style.timeAction, isLockedDuration && style.active]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
{showLabels && <Editor.Label className={style.sectionTitle}>Start time</Editor.Label>}
|
||||
<TimeInputWithButton<TimeField>
|
||||
name='timeStart'
|
||||
submitHandler={handleSubmit}
|
||||
time={timeStart}
|
||||
hasDelay={hasDelay}
|
||||
placeholder='Start'
|
||||
disabled={linkStart}
|
||||
>
|
||||
<Tooltip label='Link start to previous end' openDelay={tooltipDelayMid}>
|
||||
<InputRightElement className={activeStart} onClick={() => handleLink(!linkStart)}>
|
||||
<span className={style.timeLabel}>S</span>
|
||||
<span className={style.fourtyfive}>{linkStart ? <IoLink /> : <IoUnlink />}</span>
|
||||
</InputRightElement>
|
||||
<div className={cx([style.inputGroup, hasDelay && style.delayed])}>
|
||||
<TimeInput
|
||||
name='timeStart'
|
||||
submitHandler={handleSubmit}
|
||||
time={timeStart}
|
||||
placeholder='Start'
|
||||
align='left'
|
||||
disabled={linkStart}
|
||||
/>
|
||||
<Tooltip
|
||||
text='Link start to previous end'
|
||||
className={cx([style.timeAction, linkStart && style.active])}
|
||||
onClick={() => handleLink(!linkStart)}
|
||||
>
|
||||
<span className={style.fourtyfive}>{linkStart ? <IoLink /> : <IoUnlink />}</span>
|
||||
</Tooltip>
|
||||
</TimeInputWithButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{showLabels && <Editor.Label>End time</Editor.Label>}
|
||||
<TimeInputWithButton<TimeField>
|
||||
name='timeEnd'
|
||||
submitHandler={handleSubmit}
|
||||
time={timeEnd}
|
||||
hasDelay={hasDelay}
|
||||
disabled={isLockedDuration}
|
||||
placeholder='End'
|
||||
>
|
||||
<Tooltip label='Lock end' openDelay={tooltipDelayMid}>
|
||||
<InputRightElement
|
||||
className={activeEnd}
|
||||
onClick={() => handleChangeStrategy(TimeStrategy.LockEnd)}
|
||||
data-testid='lock__end'
|
||||
>
|
||||
<span className={style.timeLabel}>E</span>
|
||||
{isLockedEnd ? <IoLockClosed /> : <IoLockOpenOutline />}
|
||||
</InputRightElement>
|
||||
<div className={cx([style.inputGroup, hasDelay && style.delayed])}>
|
||||
<TimeInput
|
||||
name='timeEnd'
|
||||
submitHandler={handleSubmit}
|
||||
time={timeEnd}
|
||||
placeholder='End'
|
||||
align='left'
|
||||
disabled={isLockedDuration}
|
||||
/>
|
||||
<Tooltip
|
||||
text='Lock end'
|
||||
className={cx([style.timeAction, isLockedEnd && style.active])}
|
||||
onClick={() => handleChangeStrategy(TimeStrategy.LockEnd)}
|
||||
data-testid='lock__end'
|
||||
>
|
||||
{isLockedEnd ? <IoLockClosed /> : <IoLockOpenOutline />}
|
||||
</Tooltip>
|
||||
</TimeInputWithButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{showLabels && <Editor.Label>Duration</Editor.Label>}
|
||||
<TimeInputWithButton<TimeField>
|
||||
name='duration'
|
||||
submitHandler={handleSubmit}
|
||||
time={duration}
|
||||
disabled={isLockedEnd}
|
||||
placeholder='Duration'
|
||||
>
|
||||
<Tooltip label='Lock duration' openDelay={tooltipDelayMid}>
|
||||
<InputRightElement
|
||||
className={activeDuration}
|
||||
onClick={() => handleChangeStrategy(TimeStrategy.LockDuration)}
|
||||
data-testid='lock__duration'
|
||||
>
|
||||
<span className={style.timeLabel}>D</span>
|
||||
{isLockedDuration ? <IoLockClosed /> : <IoLockOpenOutline />}
|
||||
</InputRightElement>
|
||||
<div className={cx([style.inputGroup, hasDelay && style.delayed])}>
|
||||
<TimeInput
|
||||
name='duration'
|
||||
submitHandler={handleSubmit}
|
||||
time={duration}
|
||||
placeholder='Duration'
|
||||
align='left'
|
||||
disabled={isLockedEnd}
|
||||
/>
|
||||
<Tooltip
|
||||
text='Lock duration'
|
||||
className={cx([style.timeAction, isLockedDuration && style.active])}
|
||||
onClick={() => handleChangeStrategy(TimeStrategy.LockDuration)}
|
||||
data-testid='lock__duration'
|
||||
>
|
||||
{isLockedDuration ? <IoLockClosed /> : <IoLockOpenOutline />}
|
||||
</Tooltip>
|
||||
</TimeInputWithButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{warnings.length > 0 && (
|
||||
<div className={style.timerNote} data-testid='event-warning'>
|
||||
<Tooltip label={warnings.join(' - ')} openDelay={tooltipDelayFast} variant='ontime-ondark' shouldWrapChildren>
|
||||
<IoAlertCircleOutline />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Tooltip text={warnings.join(' - ')} className={style.timerNote} data-testid='event-warning' render={<span />}>
|
||||
<IoAlertCircleOutline />
|
||||
</Tooltip>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user