mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-17 21:24:11 +00:00
feat: editor layout
This commit is contained in:
committed by
Carlos Valente
parent
967e92e2c8
commit
da02ecd113
@@ -11,6 +11,11 @@ $table-header-font-size: calc(1rem - 2px);
|
||||
color: $ui-white;
|
||||
padding-bottom: 70vh; // allow focus to reach last elements
|
||||
|
||||
:is([data-target='small-device']) & {
|
||||
width: max-content;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
thead {
|
||||
tr {
|
||||
&::before {
|
||||
|
||||
@@ -21,8 +21,7 @@ import DelayRow from './cuesheet-table-elements/DelayRow';
|
||||
import EventRow from './cuesheet-table-elements/EventRow';
|
||||
import GroupRow from './cuesheet-table-elements/GroupRow';
|
||||
import MilestoneRow from './cuesheet-table-elements/MilestoneRow';
|
||||
import CuesheetTableMenu from './cuesheet-table-menu/CuesheetTableMenu';
|
||||
import EditorTableMenu from './cuesheet-table-menu/EditorTableMenu';
|
||||
import TableMenu from './cuesheet-table-menu/TableMenu';
|
||||
import CuesheetTableSettings from './cuesheet-table-settings/CuesheetTableSettings';
|
||||
import { useColumnOrder, useColumnSizes, useColumnVisibility } from './useColumnManager';
|
||||
|
||||
@@ -45,7 +44,6 @@ export default function CuesheetTable({ columns, cuesheetMode, tableRoot = 'cues
|
||||
|
||||
const selectedEventId = useSelectedEventId();
|
||||
const cursor = useEventSelection((state) => state.cursor);
|
||||
const scrollToEntry = useEventSelection((state) => state.scrollToEntry);
|
||||
const setScrollHandler = useEventSelection((state) => state.setScrollHandler);
|
||||
|
||||
const virtuosoRef = useRef<TableVirtuosoHandle | null>(null);
|
||||
@@ -116,18 +114,23 @@ export default function CuesheetTable({ columns, cuesheetMode, tableRoot = 'cues
|
||||
setColumnSizing({});
|
||||
}, [setColumnSizing]);
|
||||
|
||||
// Auto-scroll only in run mode, routed through the shared scroll handler
|
||||
// in Run mode, follow the current event
|
||||
useEffect(() => {
|
||||
if (cuesheetMode !== AppMode.Run || !selectedEventId) {
|
||||
if (virtuosoRef.current === null || cuesheetMode !== AppMode.Run || !selectedEventId) {
|
||||
return;
|
||||
}
|
||||
|
||||
scrollToEntry(selectedEventId);
|
||||
}, [cuesheetMode, data, selectedEventId, scrollToEntry]);
|
||||
const eventIndex = data.findIndex((event) => event.id === selectedEventId);
|
||||
if (eventIndex === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
virtuosoRef.current.scrollToIndex({ index: eventIndex, behavior: 'auto', align: 'start', offset: -50 });
|
||||
}, [cuesheetMode, data, selectedEventId]);
|
||||
|
||||
// Provide an imperative scroll handler for explicit jumps (finder/keyboard)
|
||||
useEffect(() => {
|
||||
setScrollHandler(`cuesheet-table-${tableRoot}`, (entryId) => {
|
||||
const handler = (entryId: string) => {
|
||||
if (virtuosoRef.current === null) {
|
||||
return;
|
||||
}
|
||||
@@ -137,13 +140,15 @@ export default function CuesheetTable({ columns, cuesheetMode, tableRoot = 'cues
|
||||
return;
|
||||
}
|
||||
|
||||
virtuosoRef.current.scrollToIndex({ index: eventIndex, behavior: 'smooth', align: 'start', offset: -50 });
|
||||
});
|
||||
virtuosoRef.current.scrollToIndex({ index: eventIndex, behavior: 'auto', align: 'start', offset: -50 });
|
||||
};
|
||||
|
||||
setScrollHandler(handler);
|
||||
|
||||
return () => {
|
||||
setScrollHandler(`cuesheet-table-${tableRoot}`, null);
|
||||
setScrollHandler(null);
|
||||
};
|
||||
}, [data, setScrollHandler, tableRoot]);
|
||||
}, [data, setScrollHandler]);
|
||||
|
||||
/**
|
||||
* To improve performance on resizing, we memoise the column sizes
|
||||
@@ -174,7 +179,6 @@ export default function CuesheetTable({ columns, cuesheetMode, tableRoot = 'cues
|
||||
|
||||
// control components need different implementations for handling permissions
|
||||
const TableRootSettings = tableRoot === 'editor' ? EditorTableSettings : CuesheetTableSettings;
|
||||
const TableMenu = tableRoot === 'editor' ? EditorTableMenu : CuesheetTableMenu;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -187,6 +191,7 @@ export default function CuesheetTable({ columns, cuesheetMode, tableRoot = 'cues
|
||||
<TableVirtuoso
|
||||
ref={virtuosoRef}
|
||||
data={data}
|
||||
style={tableRoot === 'editor' ? { paddingLeft: '1rem' } : undefined}
|
||||
increaseViewportBy={{ top: 100, bottom: 200 }}
|
||||
components={{
|
||||
EmptyPlaceholder: () => <EmptyTableBody text='No data in rundown' />,
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
import { memo } from 'react';
|
||||
import { IoAdd, IoArrowDown, IoArrowUp, IoDuplicateOutline, IoOptions, IoTrash } from 'react-icons/io5';
|
||||
import { SupportedEntry } from 'ontime-types';
|
||||
|
||||
import { PositionedDropdownMenu } from '../../../../common/components/dropdown-menu/DropdownMenu';
|
||||
import { useEntryActionsContext } from '../../../../common/context/EntryActionsContext';
|
||||
import { useCuesheetEditModal } from '../../cuesheet-edit-modal/useCuesheetEditModal';
|
||||
|
||||
import { useCuesheetTableMenu } from './useCuesheetTableMenu';
|
||||
|
||||
export default memo(EditorTableMenu);
|
||||
|
||||
function EditorTableMenu() {
|
||||
const { isOpen, entryId, entryIndex, parentId, flag, position, closeMenu } = useCuesheetTableMenu();
|
||||
const { addEntry, clone, deleteEntry, move, updateEntry } = useEntryActionsContext();
|
||||
const showModal = useCuesheetEditModal((state) => state.setEditableEntry);
|
||||
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<PositionedDropdownMenu
|
||||
isOpen
|
||||
onClose={closeMenu}
|
||||
items={[
|
||||
{
|
||||
type: 'item',
|
||||
label: 'Edit...',
|
||||
onClick: () => showModal(entryId),
|
||||
icon: IoOptions,
|
||||
},
|
||||
{ type: 'divider' },
|
||||
{
|
||||
type: 'item',
|
||||
label: flag ? 'Remove flag' : 'Add flag',
|
||||
onClick: () => updateEntry({ id: entryId, flag: !flag }),
|
||||
icon: IoDuplicateOutline,
|
||||
disabled: flag === null,
|
||||
},
|
||||
{ type: 'divider' },
|
||||
{
|
||||
type: 'item',
|
||||
label: 'Add event above',
|
||||
onClick: () => addEntry({ type: SupportedEntry.Event, parent: parentId }, { before: entryId }),
|
||||
icon: IoAdd,
|
||||
},
|
||||
{
|
||||
type: 'item',
|
||||
label: 'Add event below',
|
||||
onClick: () => addEntry({ type: SupportedEntry.Event, parent: parentId }, { after: entryId }),
|
||||
icon: IoAdd,
|
||||
},
|
||||
{
|
||||
type: 'item',
|
||||
label: 'Clone event',
|
||||
onClick: () => clone(entryId),
|
||||
icon: IoDuplicateOutline,
|
||||
},
|
||||
{ type: 'divider' },
|
||||
{
|
||||
type: 'item',
|
||||
label: 'Move up',
|
||||
onClick: () => move(entryId, 'up'),
|
||||
icon: IoArrowUp,
|
||||
disabled: entryIndex < 1,
|
||||
},
|
||||
{
|
||||
type: 'item',
|
||||
label: 'Move down',
|
||||
onClick: () => move(entryId, 'down'),
|
||||
icon: IoArrowDown,
|
||||
},
|
||||
{ type: 'divider' },
|
||||
{
|
||||
type: 'item',
|
||||
label: 'Delete',
|
||||
onClick: () => deleteEntry([entryId]),
|
||||
icon: IoTrash,
|
||||
},
|
||||
]}
|
||||
position={position}
|
||||
/>
|
||||
);
|
||||
}
|
||||
+4
-4
@@ -4,17 +4,17 @@ import { SupportedEntry } from 'ontime-types';
|
||||
|
||||
import { PositionedDropdownMenu } from '../../../../common/components/dropdown-menu/DropdownMenu';
|
||||
import { useEntryActionsContext } from '../../../../common/context/EntryActionsContext';
|
||||
import { useCuesheetEditModal } from '../../cuesheet-edit-modal/useCuesheetEditModal';
|
||||
import { useEditModal } from '../../cuesheet-edit-modal/useEditModal';
|
||||
import { useCuesheetPermissions } from '../../useTablePermissions';
|
||||
|
||||
import { useCuesheetTableMenu } from './useCuesheetTableMenu';
|
||||
|
||||
export default memo(CuesheetTableMenu);
|
||||
export default memo(TableMenu);
|
||||
|
||||
function CuesheetTableMenu() {
|
||||
function TableMenu() {
|
||||
const { isOpen, entryId, entryIndex, parentId, flag, position, closeMenu } = useCuesheetTableMenu();
|
||||
const { addEntry, clone, deleteEntry, move, updateEntry } = useEntryActionsContext();
|
||||
const showModal = useCuesheetEditModal((state) => state.setEditableEntry);
|
||||
const showModal = useEditModal((state) => state.setEditableEntry);
|
||||
const permissions = useCuesheetPermissions();
|
||||
|
||||
if (!isOpen) {
|
||||
Reference in New Issue
Block a user