fix: recover cursor logic (#773)

This commit is contained in:
Carlos Valente
2024-02-13 18:43:41 +01:00
committed by GitHub
parent 67c448572c
commit 71dace669b
12 changed files with 59 additions and 38 deletions
@@ -17,8 +17,9 @@ function persistModeToSession(mode: AppMode) {
type AppModeStore = {
mode: AppMode;
cursor: string | null;
setMode: (mode: AppMode) => void;
cursor: string | null;
setCursor: (cursor: string | null) => void;
};
export const useAppMode = create<AppModeStore>()((set) => ({
@@ -31,4 +32,5 @@ export const useAppMode = create<AppModeStore>()((set) => ({
return { mode };
});
},
setCursor: (cursor: string | null) => set(() => ({ cursor })),
}));
+14 -10
View File
@@ -34,7 +34,7 @@ export default function Rundown({ data }: RundownProps) {
const showQuickEntry = eventSettings.showQuickEntry;
// cursor
const { cursor, mode: appMode } = useAppMode();
const { cursor, mode: appMode, setCursor } = useAppMode();
const viewFollowsCursor = appMode === AppMode.Run;
const cursorRef = useRef<HTMLDivElement | null>(null);
const scrollRef = useRef<HTMLDivElement | null>(null);
@@ -95,9 +95,9 @@ export default function Rundown({ data }: RundownProps) {
return;
}
const nextEvent =
cursor == null ? getFirstNormal(rundown, order) : getNextNormal(rundown, order, cursor)?.nextEvent;
cursor === null ? getFirstNormal(rundown, order) : getNextNormal(rundown, order, cursor)?.nextEvent;
if (nextEvent) {
// moveCursorTo(nextEvent.id, nextEvent.type === SupportedEvent.Event);
setCursor(nextEvent.id);
}
break;
}
@@ -107,9 +107,11 @@ export default function Rundown({ data }: RundownProps) {
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- we check for this before
const previousEvent =
cursor == null ? getFirstNormal(rundown, order) : getPreviousNormal(rundown, order, cursor).previousEvent;
cursor === null
? getFirstNormal(rundown, order)
: getPreviousNormal(rundown, order, cursor).previousEvent;
if (previousEvent) {
// moveCursorTo(previousEvent.id, previousEvent.type === SupportedEvent.Event);
setCursor(previousEvent.id);
}
break;
}
@@ -138,11 +140,13 @@ export default function Rundown({ data }: RundownProps) {
if (order.length < 2 || cursor == null) {
return;
}
// Alt + Ctrl + Arrow Down
if (event.code == 'ArrowDown') {
const { nextEvent, nextIndex } = getNextNormal(rundown, order, cursor);
if (nextEvent && nextIndex !== null) {
reorderEvent(cursor, nextIndex - 1, nextIndex);
}
// Alt + Ctrl + Arrow Up
} else if (event.code == 'ArrowUp') {
const { previousEvent, previousIndex } = getPreviousNormal(rundown, order, cursor);
if (previousEvent && previousIndex !== null) {
@@ -151,7 +155,7 @@ export default function Rundown({ data }: RundownProps) {
}
}
},
[cursor, insertAtCursor, order, rundown, reorderEvent],
[order, cursor, rundown, setCursor, insertAtCursor, reorderEvent],
);
// we copy the state from the store here
@@ -231,10 +235,10 @@ export default function Rundown({ data }: RundownProps) {
previousEventId = event.id;
}
const isLast = index === order.length - 1;
const isSelected = featureData?.selectedEventId === event.id;
const isLoaded = featureData?.selectedEventId === event.id;
const isNext = featureData?.nextEventId === event.id;
const hasCursor = event.id === cursor;
if (isSelected) {
if (isLoaded) {
isPast = false;
}
@@ -248,12 +252,12 @@ export default function Rundown({ data }: RundownProps) {
isPast={isPast}
eventIndex={eventIndex}
data={event}
selected={isSelected}
loaded={isLoaded}
hasCursor={hasCursor}
next={isNext}
previousEnd={previousEnd}
previousEventId={previousEventId}
playback={isSelected ? featureData.playback : undefined}
playback={isLoaded ? featureData.playback : undefined}
isRolling={featureData.playback === Playback.Roll}
/>
</div>
@@ -19,7 +19,7 @@ interface RundownEntryProps {
type: SupportedEvent;
isPast: boolean;
data: OntimeRundownEntry;
selected: boolean;
loaded: boolean;
eventIndex: number;
hasCursor: boolean;
next: boolean;
@@ -30,7 +30,7 @@ interface RundownEntryProps {
}
export default function RundownEntry(props: RundownEntryProps) {
const { isPast, data, selected, hasCursor, next, previousEnd, previousEventId, playback, isRolling, eventIndex } =
const { isPast, data, loaded, hasCursor, next, previousEnd, previousEventId, playback, isRolling, eventIndex } =
props;
const { emitError } = useEmitLog();
const { addEvent, updateEvent, batchUpdateEvents, deleteEvent, swapEvents } = useEventAction();
@@ -140,7 +140,7 @@ export default function RundownEntry(props: RundownEntryProps) {
isPast={isPast}
next={next}
skip={data.skip}
selected={selected}
loaded={loaded}
hasCursor={hasCursor}
playback={playback}
isRolling={isRolling}
@@ -13,7 +13,8 @@ $block-bg: $gray-1250;
$block-bg2: $gray-1050; // for delay and blocks
$block-box-shadow: rgba(0, 0, 0, 0.5) 0 0 3px 2px;
$secondary-block-height: 2.5rem;
$block-cursor-color: $blue-400;
$block-selected-color: $blue-400;
$block-cursor-color: $orange-400;
@mixin block-styling() {
box-sizing: content-box;
@@ -28,7 +28,7 @@ $skip-opacity: 0.1;
--status-color-active-override: #{$green-400};
}
&.selected {
&.loaded {
background-color: $gray-1325;
}
@@ -47,6 +47,10 @@ $skip-opacity: 0.1;
@include declare-overrides;
}
&.selected {
outline: 1px solid $block-selected-color;
}
&.hasCursor {
outline: 1px solid $block-cursor-color;
}
@@ -10,6 +10,7 @@ import { IoSwapVertical } from '@react-icons/all-files/io5/IoSwapVertical';
import { EndAction, MaybeNumber, MaybeString, OntimeEvent, Playback, TimerType, TimeStrategy } from 'ontime-types';
import { useContextMenu } from '../../../common/hooks/useContextMenu';
import { useAppMode } from '../../../common/stores/appModeStore';
import copyToClipboard from '../../../common/utils/copyToClipboard';
import { cx, getAccessibleColour } from '../../../common/utils/styleUtils';
import type { EventItemActions } from '../RundownEntry';
@@ -41,7 +42,7 @@ interface EventBlockProps {
isPast: boolean;
next: boolean;
skip: boolean;
selected: boolean;
loaded: boolean;
hasCursor: boolean;
playback?: Playback;
isRolling: boolean;
@@ -77,7 +78,7 @@ export default function EventBlock(props: EventBlockProps) {
isPast,
next,
skip = false,
selected,
loaded,
hasCursor,
playback,
isRolling,
@@ -85,6 +86,7 @@ export default function EventBlock(props: EventBlockProps) {
} = props;
const { selectedEventId, setSelectedEventId, clearSelectedEventId } = useEventIdSwapping();
const { selectedEvents, setSelectedEvents } = useEventSelection();
const setCursor = useAppMode((state) => state.setCursor);
const handleRef = useRef<null | HTMLSpanElement>(null);
const [isVisible, setIsVisible] = useState(false);
@@ -205,13 +207,15 @@ export default function EventBlock(props: EventBlockProps) {
};
}, [handleRef]);
const isSelected = selectedEvents.has(eventId);
const blockClasses = cx([
style.eventBlock,
skip ? style.skip : null,
isPast ? style.past : null,
selected ? style.selected : null,
loaded ? style.loaded : null,
playback ? style[playback] : null,
selectedEvents.has(eventId) ? style.hasCursor : null,
isSelected ? style.selected : null,
hasCursor ? style.hasCursor : null,
]);
const handleFocusClick = (event: MouseEvent) => {
@@ -227,9 +231,8 @@ export default function EventBlock(props: EventBlockProps) {
// UI indexes are 1 based
const index = eventIndex - 1;
const editMode = getSelectionMode(event);
return setSelectedEvents({ id: eventId, index, selectMode: editMode });
// moveCursorTo(eventId, true);
setSelectedEvents({ id: eventId, index, selectMode: editMode });
setCursor(eventId);
};
return (
@@ -267,7 +270,7 @@ export default function EventBlock(props: EventBlockProps) {
delay={delay}
next={next}
skip={skip}
selected={selected}
loaded={loaded}
playback={playback}
isRolling={isRolling}
actionHandler={actionHandler}
@@ -42,7 +42,7 @@ interface EventBlockInnerProps {
delay: number;
next: boolean;
skip: boolean;
selected: boolean;
loaded: boolean;
playback?: Playback;
isRolling: boolean;
actionHandler: (action: EventItemActions, payload?: any) => void;
@@ -64,7 +64,7 @@ const EventBlockInner = (props: EventBlockInnerProps) => {
delay,
next,
skip = false,
selected,
loaded,
playback,
isRolling,
actionHandler,
@@ -110,13 +110,13 @@ const EventBlockInner = (props: EventBlockInnerProps) => {
skip={skip}
isPlaying={eventIsPlaying}
isPaused={eventIsPaused}
selected={selected}
loaded={loaded}
disablePlayback={skip || isRolling}
/>
<div className={style.statusElements} id='block-status' data-ispublic={isPublic}>
<span className={style.eventNote}>{note}</span>
<div className={selected ? style.progressBg : `${style.progressBg} ${style.hidden}`}>
{selected && <EventBlockProgressBar playback={playback} />}
<div className={loaded ? style.progressBg : `${style.progressBg} ${style.hidden}`}>
{loaded && <EventBlockProgressBar playback={playback} />}
</div>
<div className={style.eventStatus} tabIndex={-1}>
<Tooltip label={`Time type: ${timerType}`} {...tooltipProps}>
@@ -137,7 +137,7 @@ const EventBlockInner = (props: EventBlockInnerProps) => {
</div>
</div>
<div className={style.eventActions}>
<BlockActionMenu showClone enableDelete={!selected} actionHandler={actionHandler} />
<BlockActionMenu showClone enableDelete={!loaded} actionHandler={actionHandler} />
</div>
</>
);
@@ -34,7 +34,7 @@ export default function BlockActionMenu(props: BlockActionMenuProps) {
aria-label='Event options'
icon={<IoEllipsisHorizontal />}
tabIndex={-1}
variant='ontime-subtle-white'
variant='ontime-ghosted-white'
size='sm'
className={className}
/>
@@ -32,12 +32,12 @@ interface EventBlockPlaybackProps {
skip: boolean;
isPlaying: boolean;
isPaused: boolean;
selected: boolean;
loaded: boolean;
disablePlayback: boolean;
}
const EventBlockPlayback = (props: EventBlockPlaybackProps) => {
const { eventId, skip, isPlaying, isPaused, selected, disablePlayback } = props;
const { eventId, skip, isPlaying, isPaused, loaded, disablePlayback } = props;
const { updateEvent } = useEventAction();
const toggleSkip = () => {
@@ -93,7 +93,7 @@ const EventBlockPlayback = (props: EventBlockPlaybackProps) => {
{...blockBtnStyle}
clickHandler={toggleSkip}
tabIndex={-1}
isDisabled={selected}
isDisabled={loaded}
/>
<TooltipActionBtn
variant='ontime-subtle-white'
@@ -15,8 +15,6 @@
.quickBtn {
font-weight: 400;
width: auto;
padding: 0 1rem;
}
}
@@ -25,7 +23,7 @@
padding: 0 0.25rem;
color: $label-gray;
border-radius: 2px;
background-color: rgba(0, 0, 0, 0.1);
background-color: $black-10
}
.options {
@@ -1,5 +1,6 @@
import { memo, useCallback, useRef } from 'react';
import { Button, Checkbox, Tooltip } from '@chakra-ui/react';
import { IoAdd } from '@react-icons/all-files/io5/IoAdd';
import { SupportedEvent } from 'ontime-types';
import { useEventAction } from '../../../common/hooks/useEventAction';
@@ -82,6 +83,7 @@ const QuickAddBlock = (props: QuickAddBlockProps) => {
variant='ontime-subtle-white'
className={style.quickBtn}
data-testid='quick-add-event'
leftIcon={<IoAdd />}
>
Event {showKbd && <span className={style.keyboard}>{`${deviceAlt} + E`}</span>}
</Button>
@@ -94,6 +96,7 @@ const QuickAddBlock = (props: QuickAddBlockProps) => {
disabled={disableAddDelay}
className={style.quickBtn}
data-testid='quick-add-delay'
leftIcon={<IoAdd />}
>
Delay {showKbd && <span className={style.keyboard}>{`${deviceAlt} + D`}</span>}
</Button>
@@ -106,6 +109,7 @@ const QuickAddBlock = (props: QuickAddBlockProps) => {
disabled={disableAddBlock}
className={style.quickBtn}
data-testid='quick-add-block'
leftIcon={<IoAdd />}
>
Block {showKbd && <span className={style.keyboard}>{`${deviceAlt} + B`}</span>}
</Button>
+6 -1
View File
@@ -52,7 +52,12 @@ export const ontimeButtonGhostedWhite = {
...ontimeButtonSubtle,
backgroundColor: 'transparent',
color: 'white',
_hover: { background: '#ebedf0', color: '#333' },
_hover: {
background: '#404040', // $gray-1000
},
_active: {
background: '#2d2d2d', // $gray-1100
},
};
export const ontimeButtonGhosted = {