mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-26 17:39:58 +00:00
refactor: improve editor and cuesheet headers
- consistent behaviour for app mode - improve navigation
This commit is contained in:
committed by
Carlos Valente
parent
79bcc179ba
commit
6facd6a666
@@ -11,6 +11,11 @@
|
|||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px solid $blue-500;
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
|
|||||||
@@ -33,5 +33,5 @@ interface SeparatorProps extends HTMLAttributes<HTMLDivElement> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Separator({ className, orientation = 'vertical', ...elementProps }: SeparatorProps) {
|
export function Separator({ className, orientation = 'vertical', ...elementProps }: SeparatorProps) {
|
||||||
return <div className={cx([style.separator, style[orientation], className])} {...elementProps} />;
|
return <div className={cx([style.separator, style[orientation], className])} role='separator' {...elementProps} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
import { create } from 'zustand';
|
|
||||||
|
|
||||||
export enum AppMode {
|
|
||||||
Run = 'run',
|
|
||||||
Edit = 'edit',
|
|
||||||
}
|
|
||||||
|
|
||||||
const appModeKey = 'ontime-app-mode';
|
|
||||||
|
|
||||||
function getModeFromSession() {
|
|
||||||
return sessionStorage.getItem(appModeKey) === AppMode.Run ? AppMode.Run : AppMode.Edit;
|
|
||||||
}
|
|
||||||
|
|
||||||
function persistModeToSession(mode: AppMode) {
|
|
||||||
sessionStorage.setItem(appModeKey, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
type AppModeStore = {
|
|
||||||
mode: AppMode;
|
|
||||||
setMode: (mode: AppMode) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useAppMode = create<AppModeStore>()((set) => ({
|
|
||||||
mode: getModeFromSession(),
|
|
||||||
setMode: (mode: AppMode) => {
|
|
||||||
persistModeToSession(mode);
|
|
||||||
|
|
||||||
return set(() => {
|
|
||||||
return { mode };
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
@@ -20,6 +20,11 @@ $button-color-white: $gray-50;
|
|||||||
opacity: $opacity-disabled;
|
opacity: $opacity-disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px solid $blue-500;
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover:not(:disabled) {
|
&:hover:not(:disabled) {
|
||||||
color: $button-color-white;
|
color: $button-color-white;
|
||||||
background-color: $theme-color;
|
background-color: $theme-color;
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ import {
|
|||||||
import { type EventOptions, useEntryActions } from '../../common/hooks/useEntryAction';
|
import { type EventOptions, useEntryActions } from '../../common/hooks/useEntryAction';
|
||||||
import useFollowComponent from '../../common/hooks/useFollowComponent';
|
import useFollowComponent from '../../common/hooks/useFollowComponent';
|
||||||
import { useRundownEditor } from '../../common/hooks/useSocket';
|
import { useRundownEditor } from '../../common/hooks/useSocket';
|
||||||
import { AppMode, useAppMode } from '../../common/stores/appModeStore';
|
|
||||||
import { useEntryCopy } from '../../common/stores/entryCopyStore';
|
import { useEntryCopy } from '../../common/stores/entryCopyStore';
|
||||||
import { cloneEvent } from '../../common/utils/clone';
|
import { cloneEvent } from '../../common/utils/clone';
|
||||||
|
import { AppMode, sessionKeys } from '../../ontimeConfig';
|
||||||
|
|
||||||
import QuickAddBlock from './quick-add-block/QuickAddBlock';
|
import QuickAddBlock from './quick-add-block/QuickAddBlock';
|
||||||
import BlockEnd from './rundown-block/BlockEnd';
|
import BlockEnd from './rundown-block/BlockEnd';
|
||||||
@@ -70,12 +70,15 @@ export default function Rundown({ data }: RundownProps) {
|
|||||||
const { entryCopyId, setEntryCopyId } = useEntryCopy();
|
const { entryCopyId, setEntryCopyId } = useEntryCopy();
|
||||||
|
|
||||||
// cursor
|
// cursor
|
||||||
const { mode: appMode } = useAppMode();
|
const [editorMode] = useSessionStorage<AppMode>({
|
||||||
|
key: sessionKeys.editorMode,
|
||||||
|
defaultValue: AppMode.Edit,
|
||||||
|
});
|
||||||
const { clearSelectedEvents, setSelectedEvents, cursor } = useEventSelection();
|
const { clearSelectedEvents, setSelectedEvents, cursor } = useEventSelection();
|
||||||
|
|
||||||
const cursorRef = useRef<HTMLDivElement | null>(null);
|
const cursorRef = useRef<HTMLDivElement | null>(null);
|
||||||
const scrollRef = useRef<HTMLDivElement | null>(null);
|
const scrollRef = useRef<HTMLDivElement | null>(null);
|
||||||
useFollowComponent({ followRef: cursorRef, scrollRef, doFollow: appMode === AppMode.Run });
|
useFollowComponent({ followRef: cursorRef, scrollRef, doFollow: editorMode === AppMode.Run });
|
||||||
|
|
||||||
// DND KIT
|
// DND KIT
|
||||||
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 10 } }));
|
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 10 } }));
|
||||||
@@ -283,12 +286,12 @@ export default function Rundown({ data }: RundownProps) {
|
|||||||
|
|
||||||
// in run mode, we follow selection
|
// in run mode, we follow selection
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (appMode !== AppMode.Run || !featureData?.selectedEventId) {
|
if (editorMode !== AppMode.Run || !featureData?.selectedEventId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const index = order.findIndex((id) => id === featureData.selectedEventId);
|
const index = order.findIndex((id) => id === featureData.selectedEventId);
|
||||||
setSelectedEvents({ id: featureData.selectedEventId, selectMode: 'click', index });
|
setSelectedEvents({ id: featureData.selectedEventId, selectMode: 'click', index });
|
||||||
}, [appMode, featureData.selectedEventId, order, setSelectedEvents]);
|
}, [editorMode, featureData.selectedEventId, order, setSelectedEvents]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On drag end, we reorder the events
|
* On drag end, we reorder the events
|
||||||
@@ -359,7 +362,7 @@ export default function Rundown({ data }: RundownProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 1. gather presentation options
|
// 1. gather presentation options
|
||||||
const isEditMode = appMode === AppMode.Edit;
|
const isEditMode = editorMode === AppMode.Edit;
|
||||||
|
|
||||||
// 2. initialise rundown metadata
|
// 2. initialise rundown metadata
|
||||||
const { metadata, process } = makeRundownMetadata(featureData?.selectedEventId);
|
const { metadata, process } = makeRundownMetadata(featureData?.selectedEventId);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
import { useSessionStorage } from '@mantine/hooks';
|
||||||
|
|
||||||
import { ContextMenu } from '../../common/components/context-menu/ContextMenu';
|
import { ContextMenu } from '../../common/components/context-menu/ContextMenu';
|
||||||
import { Corner } from '../../common/components/editor-utils/EditorUtils';
|
import { Corner } from '../../common/components/editor-utils/EditorUtils';
|
||||||
@@ -6,9 +7,9 @@ import ErrorBoundary from '../../common/components/error-boundary/ErrorBoundary'
|
|||||||
import ViewNavigationMenu from '../../common/components/navigation-menu/ViewNavigationMenu';
|
import ViewNavigationMenu from '../../common/components/navigation-menu/ViewNavigationMenu';
|
||||||
import ProtectRoute from '../../common/components/protect-route/ProtectRoute';
|
import ProtectRoute from '../../common/components/protect-route/ProtectRoute';
|
||||||
import { useIsSmallDevice } from '../../common/hooks/useIsSmallDevice';
|
import { useIsSmallDevice } from '../../common/hooks/useIsSmallDevice';
|
||||||
import { useAppMode } from '../../common/stores/appModeStore';
|
|
||||||
import { handleLinks } from '../../common/utils/linkUtils';
|
import { handleLinks } from '../../common/utils/linkUtils';
|
||||||
import { cx } from '../../common/utils/styleUtils';
|
import { cx } from '../../common/utils/styleUtils';
|
||||||
|
import { AppMode, sessionKeys } from '../../ontimeConfig';
|
||||||
|
|
||||||
import RundownEntryEditor from './entry-editor/RundownEntryEditor';
|
import RundownEntryEditor from './entry-editor/RundownEntryEditor';
|
||||||
import FinderPlacement from './placements/FinderPlacement';
|
import FinderPlacement from './placements/FinderPlacement';
|
||||||
@@ -20,7 +21,10 @@ export default memo(RundownExport);
|
|||||||
|
|
||||||
function RundownExport() {
|
function RundownExport() {
|
||||||
const isExtracted = window.location.pathname.includes('/rundown');
|
const isExtracted = window.location.pathname.includes('/rundown');
|
||||||
const appMode = useAppMode((state) => state.mode);
|
const [editorMode] = useSessionStorage({
|
||||||
|
key: sessionKeys.editorMode,
|
||||||
|
defaultValue: AppMode.Edit,
|
||||||
|
});
|
||||||
const isSmallDevice = useIsSmallDevice();
|
const isSmallDevice = useIsSmallDevice();
|
||||||
|
|
||||||
if (isSmallDevice && isExtracted) {
|
if (isSmallDevice && isExtracted) {
|
||||||
@@ -45,7 +49,7 @@ function RundownExport() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hideSideBar = isExtracted && appMode === 'run';
|
const hideSideBar = isExtracted && editorMode === 'run';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProtectRoute permission='editor'>
|
<ProtectRoute permission='editor'>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { memo, useRef } from 'react';
|
import { memo, useRef } from 'react';
|
||||||
import { IoAdd } from 'react-icons/io5';
|
import { IoAdd } from 'react-icons/io5';
|
||||||
|
import { Toolbar } from '@base-ui-components/react/toolbar';
|
||||||
import { MaybeString, SupportedEntry } from 'ontime-types';
|
import { MaybeString, SupportedEntry } from 'ontime-types';
|
||||||
|
|
||||||
import Button from '../../../common/components/buttons/Button';
|
import Button from '../../../common/components/buttons/Button';
|
||||||
@@ -64,21 +65,23 @@ function QuickAddBlock({ previousEventId, parentBlock, backgroundColor }: QuickA
|
|||||||
const blockColour = backgroundColor === '' ? '#9d9d9d' : backgroundColor;
|
const blockColour = backgroundColor === '' ? '#9d9d9d' : backgroundColor;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.quickAdd} style={blockColour ? { '--user-bg': blockColour } : {}}>
|
<Toolbar.Root className={style.quickAdd} style={blockColour ? { '--user-bg': blockColour } : {}}>
|
||||||
<Button onClick={addEvent} size='small' variant='subtle-white'>
|
<Toolbar.Button render={<Button size='small' variant='subtle-white' />} onClick={addEvent}>
|
||||||
<IoAdd />
|
<IoAdd />
|
||||||
Event
|
Event
|
||||||
</Button>
|
</Toolbar.Button>
|
||||||
<Button onClick={addDelay} size='small' variant='subtle-white'>
|
|
||||||
|
<Toolbar.Button render={<Button size='small' variant='subtle-white' />} onClick={addDelay}>
|
||||||
<IoAdd />
|
<IoAdd />
|
||||||
Delay
|
Delay
|
||||||
</Button>
|
</Toolbar.Button>
|
||||||
|
|
||||||
{parentBlock === null && (
|
{parentBlock === null && (
|
||||||
<Button onClick={addBlock} size='small' variant='subtle-white'>
|
<Toolbar.Button render={<Button size='small' variant='subtle-white' />} onClick={addBlock}>
|
||||||
<IoAdd />
|
<IoAdd />
|
||||||
Block
|
Block
|
||||||
</Button>
|
</Toolbar.Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</Toolbar.Root>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** styles should match CuesheetTableSettings.module.scss */
|
||||||
.group {
|
.group {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -19,7 +20,8 @@
|
|||||||
height: 2rem;
|
height: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
/** styles should match CuesheetTableSettings.module.scss */
|
||||||
|
.radioButton {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -34,6 +36,7 @@
|
|||||||
|
|
||||||
&:focus-visible {
|
&:focus-visible {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
outline: 1px solid $blue-500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover:not(:disabled):not(:active) {
|
&:hover:not(:disabled):not(:active) {
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ import { memo } from 'react';
|
|||||||
import { Toggle } from '@base-ui-components/react/toggle';
|
import { Toggle } from '@base-ui-components/react/toggle';
|
||||||
import { ToggleGroup } from '@base-ui-components/react/toggle-group';
|
import { ToggleGroup } from '@base-ui-components/react/toggle-group';
|
||||||
import { Toolbar } from '@base-ui-components/react/toolbar';
|
import { Toolbar } from '@base-ui-components/react/toolbar';
|
||||||
|
import { useSessionStorage } from '@mantine/hooks';
|
||||||
import { OffsetMode } from 'ontime-types';
|
import { OffsetMode } from 'ontime-types';
|
||||||
|
|
||||||
import * as Editor from '../../../common/components/editor-utils/EditorUtils';
|
import * as Editor from '../../../common/components/editor-utils/EditorUtils';
|
||||||
import { setOffsetMode, useOffsetMode } from '../../../common/hooks/useSocket';
|
import { setOffsetMode, useOffsetMode } from '../../../common/hooks/useSocket';
|
||||||
import { AppMode, useAppMode } from '../../../common/stores/appModeStore';
|
import { AppMode, sessionKeys } from '../../../ontimeConfig';
|
||||||
|
|
||||||
import RundownMenu from './RundownMenu';
|
import RundownMenu from './RundownMenu';
|
||||||
|
|
||||||
@@ -14,8 +15,7 @@ import style from './RundownHeader.module.scss';
|
|||||||
|
|
||||||
export default memo(RundownHeader);
|
export default memo(RundownHeader);
|
||||||
function RundownHeader() {
|
function RundownHeader() {
|
||||||
const appMode = useAppMode((state) => state.mode);
|
const [editorMode, setEditorMode] = useSessionStorage({ key: sessionKeys.editorMode, defaultValue: AppMode.Edit });
|
||||||
const setAppMode = useAppMode((state) => state.setMode);
|
|
||||||
|
|
||||||
const { offsetMode } = useOffsetMode();
|
const { offsetMode } = useOffsetMode();
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ function RundownHeader() {
|
|||||||
// we need to stop user from deselecting a mode
|
// we need to stop user from deselecting a mode
|
||||||
const newValue = mode.at(0);
|
const newValue = mode.at(0);
|
||||||
if (!newValue) return;
|
if (!newValue) return;
|
||||||
setAppMode(newValue);
|
setEditorMode(newValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleOffsetMode = (mode: OffsetMode[]) => {
|
const toggleOffsetMode = (mode: OffsetMode[]) => {
|
||||||
@@ -35,11 +35,11 @@ function RundownHeader() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Toolbar.Root className={style.header}>
|
<Toolbar.Root className={style.header}>
|
||||||
<ToggleGroup value={[appMode]} onValueChange={toggleAppMode} className={style.group}>
|
<ToggleGroup value={[editorMode]} onValueChange={toggleAppMode} className={style.group}>
|
||||||
<Toolbar.Button render={<Toggle />} value={AppMode.Run} className={style.button}>
|
<Toolbar.Button render={<Toggle />} value={AppMode.Run} className={style.radioButton}>
|
||||||
Run
|
Run
|
||||||
</Toolbar.Button>
|
</Toolbar.Button>
|
||||||
<Toolbar.Button render={<Toggle />} value={AppMode.Edit} className={style.button}>
|
<Toolbar.Button render={<Toggle />} value={AppMode.Edit} className={style.radioButton}>
|
||||||
Edit
|
Edit
|
||||||
</Toolbar.Button>
|
</Toolbar.Button>
|
||||||
</ToggleGroup>
|
</ToggleGroup>
|
||||||
@@ -47,10 +47,10 @@ function RundownHeader() {
|
|||||||
<Editor.Separator className={style.separator} />
|
<Editor.Separator className={style.separator} />
|
||||||
|
|
||||||
<ToggleGroup value={[offsetMode]} onValueChange={toggleOffsetMode} className={style.group}>
|
<ToggleGroup value={[offsetMode]} onValueChange={toggleOffsetMode} className={style.group}>
|
||||||
<Toolbar.Button render={<Toggle />} value={OffsetMode.Absolute} className={style.button}>
|
<Toolbar.Button render={<Toggle />} value={OffsetMode.Absolute} className={style.radioButton}>
|
||||||
Absolute
|
Absolute
|
||||||
</Toolbar.Button>
|
</Toolbar.Button>
|
||||||
<Toolbar.Button render={<Toggle />} value={OffsetMode.Relative} className={style.button}>
|
<Toolbar.Button render={<Toggle />} value={OffsetMode.Relative} className={style.radioButton}>
|
||||||
Relative
|
Relative
|
||||||
</Toolbar.Button>
|
</Toolbar.Button>
|
||||||
</ToggleGroup>
|
</ToggleGroup>
|
||||||
|
|||||||
@@ -2,18 +2,21 @@ import { memo } from 'react';
|
|||||||
import { Toggle } from '@base-ui-components/react/toggle';
|
import { Toggle } from '@base-ui-components/react/toggle';
|
||||||
import { ToggleGroup } from '@base-ui-components/react/toggle-group';
|
import { ToggleGroup } from '@base-ui-components/react/toggle-group';
|
||||||
import { Toolbar } from '@base-ui-components/react/toolbar';
|
import { Toolbar } from '@base-ui-components/react/toolbar';
|
||||||
|
import { useSessionStorage } from '@mantine/hooks';
|
||||||
import { OffsetMode } from 'ontime-types';
|
import { OffsetMode } from 'ontime-types';
|
||||||
|
|
||||||
import * as Editor from '../../../common/components/editor-utils/EditorUtils';
|
import * as Editor from '../../../common/components/editor-utils/EditorUtils';
|
||||||
import { setOffsetMode, useOffsetMode } from '../../../common/hooks/useSocket';
|
import { setOffsetMode, useOffsetMode } from '../../../common/hooks/useSocket';
|
||||||
import { AppMode, useAppMode } from '../../../common/stores/appModeStore';
|
import { AppMode, sessionKeys } from '../../../ontimeConfig';
|
||||||
|
|
||||||
import style from './RundownHeader.module.scss';
|
import style from './RundownHeader.module.scss';
|
||||||
|
|
||||||
export default memo(RundownHeader);
|
export default memo(RundownHeader);
|
||||||
function RundownHeader() {
|
function RundownHeader() {
|
||||||
const appMode = useAppMode((state) => state.mode);
|
const [editorMode, setEditorMode] = useSessionStorage<AppMode>({
|
||||||
const setAppMode = useAppMode((state) => state.setMode);
|
key: sessionKeys.editorMode,
|
||||||
|
defaultValue: AppMode.Edit,
|
||||||
|
});
|
||||||
|
|
||||||
const { offsetMode } = useOffsetMode();
|
const { offsetMode } = useOffsetMode();
|
||||||
|
|
||||||
@@ -21,7 +24,7 @@ function RundownHeader() {
|
|||||||
// we need to stop user from deselecting a mode
|
// we need to stop user from deselecting a mode
|
||||||
const newValue = mode.at(0);
|
const newValue = mode.at(0);
|
||||||
if (!newValue) return;
|
if (!newValue) return;
|
||||||
setAppMode(newValue);
|
setEditorMode(newValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleOffsetMode = (mode: OffsetMode[]) => {
|
const toggleOffsetMode = (mode: OffsetMode[]) => {
|
||||||
@@ -33,7 +36,7 @@ function RundownHeader() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Toolbar.Root className={style.header}>
|
<Toolbar.Root className={style.header}>
|
||||||
<ToggleGroup value={[appMode]} onValueChange={toggleAppMode} className={style.group}>
|
<ToggleGroup value={[editorMode]} onValueChange={toggleAppMode} className={style.group}>
|
||||||
<Toolbar.Button render={<Toggle />} value={AppMode.Run} className={style.button}>
|
<Toolbar.Button render={<Toggle />} value={AppMode.Run} className={style.button}>
|
||||||
Run
|
Run
|
||||||
</Toolbar.Button>
|
</Toolbar.Button>
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { IoTrash } from 'react-icons/io5';
|
import { IoTrash } from 'react-icons/io5';
|
||||||
import { useDisclosure } from '@mantine/hooks';
|
import { Toolbar } from '@base-ui-components/react/toolbar';
|
||||||
|
import { useDisclosure, useSessionStorage } from '@mantine/hooks';
|
||||||
|
|
||||||
import Button from '../../../common/components/buttons/Button';
|
import Button from '../../../common/components/buttons/Button';
|
||||||
import Dialog from '../../../common/components/dialog/Dialog';
|
import Dialog from '../../../common/components/dialog/Dialog';
|
||||||
import { useEntryActions } from '../../../common/hooks/useEntryAction';
|
import { useEntryActions } from '../../../common/hooks/useEntryAction';
|
||||||
import { AppMode, useAppMode } from '../../../common/stores/appModeStore';
|
import { AppMode, sessionKeys } from '../../../ontimeConfig';
|
||||||
import { useEventSelection } from '../useEventSelection';
|
import { useEventSelection } from '../useEventSelection';
|
||||||
|
|
||||||
import style from './RundownHeader.module.scss';
|
import style from './RundownHeader.module.scss';
|
||||||
@@ -15,7 +16,10 @@ function RundownMenu() {
|
|||||||
const [isOpen, handlers] = useDisclosure();
|
const [isOpen, handlers] = useDisclosure();
|
||||||
|
|
||||||
const clearSelectedEvents = useEventSelection((state) => state.clearSelectedEvents);
|
const clearSelectedEvents = useEventSelection((state) => state.clearSelectedEvents);
|
||||||
const appMode = useAppMode((state) => state.mode);
|
const [editorMode] = useSessionStorage({
|
||||||
|
key: sessionKeys.cuesheetMode,
|
||||||
|
defaultValue: AppMode.Edit,
|
||||||
|
});
|
||||||
const { deleteAllEntries } = useEntryActions();
|
const { deleteAllEntries } = useEntryActions();
|
||||||
|
|
||||||
const deleteAll = useCallback(() => {
|
const deleteAll = useCallback(() => {
|
||||||
@@ -26,15 +30,15 @@ function RundownMenu() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Toolbar.Button
|
||||||
variant='subtle-destructive'
|
render={<Button variant='subtle-destructive' />}
|
||||||
|
onClick={handlers.open}
|
||||||
|
disabled={editorMode === AppMode.Run}
|
||||||
className={style.apart}
|
className={style.apart}
|
||||||
onClick={() => handlers.open()}
|
|
||||||
disabled={appMode === AppMode.Run}
|
|
||||||
>
|
>
|
||||||
<IoTrash />
|
<IoTrash />
|
||||||
Clear all
|
Clear all
|
||||||
</Button>
|
</Toolbar.Button>
|
||||||
<Dialog
|
<Dialog
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onClose={handlers.close}
|
onClose={handlers.close}
|
||||||
@@ -48,7 +52,7 @@ function RundownMenu() {
|
|||||||
}
|
}
|
||||||
footerElements={
|
footerElements={
|
||||||
<>
|
<>
|
||||||
<Button size='large' onClick={handlers.close}>
|
<Button variant='ghosted-white' size='large' onClick={handlers.close}>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant='destructive' size='large' onClick={deleteAll}>
|
<Button variant='destructive' size='large' onClick={deleteAll}>
|
||||||
|
|||||||
@@ -4,3 +4,13 @@ export const tooltipDelayFast = 300;
|
|||||||
|
|
||||||
export const queryRefetchInterval = 60000; // 60 seconds
|
export const queryRefetchInterval = 60000; // 60 seconds
|
||||||
export const queryRefetchIntervalSlow = 120000; // 120 seconds
|
export const queryRefetchIntervalSlow = 120000; // 120 seconds
|
||||||
|
|
||||||
|
export const sessionKeys = {
|
||||||
|
cuesheetMode: 'cuesheet-mode',
|
||||||
|
editorMode: 'editor-mode',
|
||||||
|
};
|
||||||
|
|
||||||
|
export enum AppMode {
|
||||||
|
Run = 'run',
|
||||||
|
Edit = 'edit',
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
|
import { useSessionStorage } from '@mantine/hooks';
|
||||||
import { useTableNav } from '@table-nav/react';
|
import { useTableNav } from '@table-nav/react';
|
||||||
import { ColumnDef, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
import { ColumnDef, getCoreRowModel, useReactTable } from '@tanstack/react-table';
|
||||||
import { OntimeEntry, TimeField } from 'ontime-types';
|
import { OntimeEntry, TimeField } from 'ontime-types';
|
||||||
|
|
||||||
import { useEntryActions } from '../../../common/hooks/useEntryAction';
|
import { useEntryActions } from '../../../common/hooks/useEntryAction';
|
||||||
import { useFollowSelected } from '../../../common/hooks/useFollowComponent';
|
import { useFollowSelected } from '../../../common/hooks/useFollowComponent';
|
||||||
|
import { AppMode,sessionKeys } from '../../../ontimeConfig';
|
||||||
import { usePersistedCuesheetOptions } from '../cuesheet.options';
|
import { usePersistedCuesheetOptions } from '../cuesheet.options';
|
||||||
|
|
||||||
import CuesheetBody from './cuesheet-table-elements/CuesheetBody';
|
import CuesheetBody from './cuesheet-table-elements/CuesheetBody';
|
||||||
@@ -22,11 +24,14 @@ interface CuesheetTableProps {
|
|||||||
|
|
||||||
export default function CuesheetTable({ data, columns }: CuesheetTableProps) {
|
export default function CuesheetTable({ data, columns }: CuesheetTableProps) {
|
||||||
const { updateEntry, updateTimer } = useEntryActions();
|
const { updateEntry, updateTimer } = useEntryActions();
|
||||||
const followPlayback = usePersistedCuesheetOptions((state) => state.followPlayback);
|
|
||||||
const showDelayedTimes = usePersistedCuesheetOptions((state) => state.showDelayedTimes);
|
const showDelayedTimes = usePersistedCuesheetOptions((state) => state.showDelayedTimes);
|
||||||
const hideTableSeconds = usePersistedCuesheetOptions((state) => state.hideTableSeconds);
|
const hideTableSeconds = usePersistedCuesheetOptions((state) => state.hideTableSeconds);
|
||||||
|
const [cuesheetMode] = useSessionStorage({
|
||||||
|
key: sessionKeys.cuesheetMode,
|
||||||
|
defaultValue: AppMode.Edit,
|
||||||
|
});
|
||||||
|
|
||||||
const { selectedRef, scrollRef } = useFollowSelected(followPlayback);
|
const { selectedRef, scrollRef } = useFollowSelected(cuesheetMode === AppMode.Run);
|
||||||
|
|
||||||
const { listeners } = useTableNav();
|
const { listeners } = useTableNav();
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { IoEllipsisHorizontal } from 'react-icons/io5';
|
import { IoEllipsisHorizontal } from 'react-icons/io5';
|
||||||
|
import { useSessionStorage } from '@mantine/hooks';
|
||||||
import { flexRender, Table } from '@tanstack/react-table';
|
import { flexRender, Table } from '@tanstack/react-table';
|
||||||
import { EntryId, OntimeEntry } from 'ontime-types';
|
import { EntryId, OntimeEntry } from 'ontime-types';
|
||||||
|
|
||||||
import IconButton from '../../../../common/components/buttons/IconButton';
|
import IconButton from '../../../../common/components/buttons/IconButton';
|
||||||
import { useCurrentBlockId } from '../../../../common/hooks/useSocket';
|
import { useCurrentBlockId } from '../../../../common/hooks/useSocket';
|
||||||
|
import { AppMode, sessionKeys } from '../../../../ontimeConfig';
|
||||||
import { usePersistedCuesheetOptions } from '../../cuesheet.options';
|
import { usePersistedCuesheetOptions } from '../../cuesheet.options';
|
||||||
import { useCuesheetTableMenu } from '../cuesheet-table-menu/useCuesheetTableMenu';
|
import { useCuesheetTableMenu } from '../cuesheet-table-menu/useCuesheetTableMenu';
|
||||||
|
|
||||||
@@ -22,7 +24,10 @@ export default function BlockRow({ blockId, colour, hidePast, rowId, rowIndex, t
|
|||||||
const { currentBlockId } = useCurrentBlockId();
|
const { currentBlockId } = useCurrentBlockId();
|
||||||
|
|
||||||
const hideIndexColumn = usePersistedCuesheetOptions((state) => state.hideIndexColumn);
|
const hideIndexColumn = usePersistedCuesheetOptions((state) => state.hideIndexColumn);
|
||||||
const showActionMenu = usePersistedCuesheetOptions((state) => state.showActionMenu);
|
const [cuesheetMode] = useSessionStorage<AppMode>({
|
||||||
|
key: sessionKeys.cuesheetMode,
|
||||||
|
defaultValue: AppMode.Edit,
|
||||||
|
});
|
||||||
const openMenu = useCuesheetTableMenu((store) => store.openMenu);
|
const openMenu = useCuesheetTableMenu((store) => store.openMenu);
|
||||||
|
|
||||||
if (hidePast && !currentBlockId) {
|
if (hidePast && !currentBlockId) {
|
||||||
@@ -31,7 +36,7 @@ export default function BlockRow({ blockId, colour, hidePast, rowId, rowIndex, t
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<tr className={style.blockRow} style={{ '--user-bg': colour }} data-testid='cuesheet-block'>
|
<tr className={style.blockRow} style={{ '--user-bg': colour }} data-testid='cuesheet-block'>
|
||||||
{showActionMenu && (
|
{cuesheetMode === AppMode.Edit && (
|
||||||
<td className={style.actionColumn} tabIndex={-1} role='cell'>
|
<td className={style.actionColumn} tabIndex={-1} role='cell'>
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label='Options'
|
aria-label='Options'
|
||||||
|
|||||||
+7
-2
@@ -1,8 +1,10 @@
|
|||||||
import { horizontalListSortingStrategy, SortableContext } from '@dnd-kit/sortable';
|
import { horizontalListSortingStrategy, SortableContext } from '@dnd-kit/sortable';
|
||||||
|
import { useSessionStorage } from '@mantine/hooks';
|
||||||
import { flexRender, HeaderGroup } from '@tanstack/react-table';
|
import { flexRender, HeaderGroup } from '@tanstack/react-table';
|
||||||
import { OntimeEntry } from 'ontime-types';
|
import { OntimeEntry } from 'ontime-types';
|
||||||
|
|
||||||
import { getAccessibleColour } from '../../../../common/utils/styleUtils';
|
import { getAccessibleColour } from '../../../../common/utils/styleUtils';
|
||||||
|
import { AppMode, sessionKeys } from '../../../../ontimeConfig';
|
||||||
import { usePersistedCuesheetOptions } from '../../cuesheet.options';
|
import { usePersistedCuesheetOptions } from '../../cuesheet.options';
|
||||||
|
|
||||||
import { SortableCell } from './SortableCell';
|
import { SortableCell } from './SortableCell';
|
||||||
@@ -15,7 +17,10 @@ interface CuesheetHeaderProps {
|
|||||||
|
|
||||||
export default function CuesheetHeader({ headerGroups }: CuesheetHeaderProps) {
|
export default function CuesheetHeader({ headerGroups }: CuesheetHeaderProps) {
|
||||||
const hideIndexColumn = usePersistedCuesheetOptions((state) => state.hideIndexColumn);
|
const hideIndexColumn = usePersistedCuesheetOptions((state) => state.hideIndexColumn);
|
||||||
const showActionMenu = usePersistedCuesheetOptions((state) => state.showActionMenu);
|
const [cuesheetMode] = useSessionStorage<AppMode>({
|
||||||
|
key: sessionKeys.cuesheetMode,
|
||||||
|
defaultValue: AppMode.Edit,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<thead className={style.tableHeader}>
|
<thead className={style.tableHeader}>
|
||||||
@@ -24,7 +29,7 @@ export default function CuesheetHeader({ headerGroups }: CuesheetHeaderProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<tr key={headerGroup.id}>
|
<tr key={headerGroup.id}>
|
||||||
{showActionMenu && <th className={style.actionColumn} tabIndex={-1} />}
|
{cuesheetMode === AppMode.Edit && <th className={style.actionColumn} tabIndex={-1} />}
|
||||||
{!hideIndexColumn && (
|
{!hideIndexColumn && (
|
||||||
<th className={style.indexColumn} tabIndex={-1}>
|
<th className={style.indexColumn} tabIndex={-1}>
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { MutableRefObject, useEffect, useRef } from 'react';
|
import { MutableRefObject, useEffect, useRef } from 'react';
|
||||||
import { IoEllipsisHorizontal } from 'react-icons/io5';
|
import { IoEllipsisHorizontal } from 'react-icons/io5';
|
||||||
|
import { useSessionStorage } from '@mantine/hooks';
|
||||||
import { flexRender, Table } from '@tanstack/react-table';
|
import { flexRender, Table } from '@tanstack/react-table';
|
||||||
import { OntimeEntry, OntimeEvent, RGBColour } from 'ontime-types';
|
import { OntimeEntry, OntimeEvent, RGBColour } from 'ontime-types';
|
||||||
import { colourToHex, cssOrHexToColour } from 'ontime-utils';
|
import { colourToHex, cssOrHexToColour } from 'ontime-utils';
|
||||||
|
|
||||||
import IconButton from '../../../../common/components/buttons/IconButton';
|
import IconButton from '../../../../common/components/buttons/IconButton';
|
||||||
import { cx, getAccessibleColour } from '../../../../common/utils/styleUtils';
|
import { cx, getAccessibleColour } from '../../../../common/utils/styleUtils';
|
||||||
|
import { AppMode, sessionKeys } from '../../../../ontimeConfig';
|
||||||
import { usePersistedCuesheetOptions } from '../../cuesheet.options';
|
import { usePersistedCuesheetOptions } from '../../cuesheet.options';
|
||||||
import { useCuesheetTableMenu } from '../cuesheet-table-menu/useCuesheetTableMenu';
|
import { useCuesheetTableMenu } from '../cuesheet-table-menu/useCuesheetTableMenu';
|
||||||
|
|
||||||
@@ -44,8 +46,10 @@ export default function EventRow({
|
|||||||
firstAfterBlock,
|
firstAfterBlock,
|
||||||
}: EventRowProps) {
|
}: EventRowProps) {
|
||||||
const hideIndexColumn = usePersistedCuesheetOptions((state) => state.hideIndexColumn);
|
const hideIndexColumn = usePersistedCuesheetOptions((state) => state.hideIndexColumn);
|
||||||
const showActionMenu = usePersistedCuesheetOptions((state) => state.showActionMenu);
|
const [cuesheetMode] = useSessionStorage<AppMode>({
|
||||||
const ownRef = useRef<HTMLTableRowElement>(null);
|
key: sessionKeys.cuesheetMode,
|
||||||
|
defaultValue: AppMode.Edit,
|
||||||
|
}); const ownRef = useRef<HTMLTableRowElement>(null);
|
||||||
|
|
||||||
const isVisible = useVisibleRowsStore((state) => state.visibleRows.has(rowId));
|
const isVisible = useVisibleRowsStore((state) => state.visibleRows.has(rowId));
|
||||||
|
|
||||||
@@ -86,7 +90,7 @@ export default function EventRow({
|
|||||||
ref={selectedRef ?? ownRef}
|
ref={selectedRef ?? ownRef}
|
||||||
data-testid='cuesheet-event'
|
data-testid='cuesheet-event'
|
||||||
>
|
>
|
||||||
{showActionMenu && (
|
{cuesheetMode === AppMode.Edit && (
|
||||||
<td className={style.actionColumn} tabIndex={-1} role='cell'>
|
<td className={style.actionColumn} tabIndex={-1} role='cell'>
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label='Options'
|
aria-label='Options'
|
||||||
|
|||||||
+3
-2
@@ -1,3 +1,4 @@
|
|||||||
|
import { Toolbar } from '@base-ui-components/react/toolbar';
|
||||||
import { useDisclosure } from '@mantine/hooks';
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
|
|
||||||
import Button from '../../../../common/components/buttons/Button';
|
import Button from '../../../../common/components/buttons/Button';
|
||||||
@@ -17,10 +18,10 @@ function CuesheetShareModal() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button variant='subtle' onClick={handler.open}>
|
<Toolbar.Button onClick={handler.open} render={<Button />}>
|
||||||
<RotatedLink />
|
<RotatedLink />
|
||||||
Share...
|
Share...
|
||||||
</Button>
|
</Toolbar.Button>
|
||||||
<Modal
|
<Modal
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onClose={handler.close}
|
onClose={handler.close}
|
||||||
|
|||||||
+54
-2
@@ -5,7 +5,7 @@
|
|||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
gap: 1rem;
|
||||||
font-size: $inner-section-text-size;
|
font-size: $inner-section-text-size;
|
||||||
border-radius: 3px 3px 0 0;
|
border-radius: 3px 3px 0 0;
|
||||||
}
|
}
|
||||||
@@ -39,4 +39,56 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.apart {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** styles should match RundownHeader.module.scss */
|
||||||
|
.group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2px;
|
||||||
|
padding-inline: 2px;
|
||||||
|
background: $gray-1100;
|
||||||
|
border-radius: $component-border-radius-md;
|
||||||
|
height: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** styles should match RundownHeader.module.scss */
|
||||||
|
.radioButton {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: calc(2rem - 4px); // padding inline * 2
|
||||||
|
padding-inline: 1em;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: $component-border-radius-md;
|
||||||
|
color: $gray-400;
|
||||||
|
font-size: calc(1rem - 2px);
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
background: transparent;
|
||||||
|
outline: 1px solid $blue-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover:not(:disabled):not(:active) {
|
||||||
|
background: $gray-1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: $gray-1100;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-pressed] {
|
||||||
|
background: $blue-700;
|
||||||
|
color: $ui-white;
|
||||||
|
|
||||||
|
&:hover:not(:disabled):not(:active) {
|
||||||
|
background: $blue-600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+96
-81
@@ -1,6 +1,10 @@
|
|||||||
import { memo, ReactNode } from 'react';
|
import { memo, ReactNode } from 'react';
|
||||||
import { IoChevronDown, IoLocate, IoOptions, IoSettingsOutline } from 'react-icons/io5';
|
import { IoChevronDown, IoOptions, IoSettingsOutline } from 'react-icons/io5';
|
||||||
import { Popover } from '@base-ui-components/react/popover';
|
import { Popover } from '@base-ui-components/react/popover';
|
||||||
|
import { Toggle } from '@base-ui-components/react/toggle';
|
||||||
|
import { ToggleGroup } from '@base-ui-components/react/toggle-group';
|
||||||
|
import { Toolbar } from '@base-ui-components/react/toolbar';
|
||||||
|
import { useSessionStorage } from '@mantine/hooks';
|
||||||
import type { Column } from '@tanstack/react-table';
|
import type { Column } from '@tanstack/react-table';
|
||||||
import { OntimeEntry } from 'ontime-types';
|
import { OntimeEntry } from 'ontime-types';
|
||||||
|
|
||||||
@@ -8,6 +12,8 @@ import Button from '../../../../common/components/buttons/Button';
|
|||||||
import Checkbox from '../../../../common/components/checkbox/Checkbox';
|
import Checkbox from '../../../../common/components/checkbox/Checkbox';
|
||||||
import * as Editor from '../../../../common/components/editor-utils/EditorUtils';
|
import * as Editor from '../../../../common/components/editor-utils/EditorUtils';
|
||||||
import PopoverContents from '../../../../common/components/popover/Popover';
|
import PopoverContents from '../../../../common/components/popover/Popover';
|
||||||
|
import { cx } from '../../../../common/utils/styleUtils';
|
||||||
|
import { AppMode, sessionKeys } from '../../../../ontimeConfig';
|
||||||
import { usePersistedCuesheetOptions } from '../../cuesheet.options';
|
import { usePersistedCuesheetOptions } from '../../cuesheet.options';
|
||||||
|
|
||||||
import CuesheetShareModal from './CuesheetShareModal';
|
import CuesheetShareModal from './CuesheetShareModal';
|
||||||
@@ -28,36 +34,40 @@ function CuesheetTableSettings({
|
|||||||
handleResetReordering,
|
handleResetReordering,
|
||||||
handleClearToggles,
|
handleClearToggles,
|
||||||
}: CuesheetTableSettingsProps) {
|
}: CuesheetTableSettingsProps) {
|
||||||
return (
|
const [cuesheetMode, setCuesheetMode] = useSessionStorage({
|
||||||
<div className={style.tableSettings}>
|
key: sessionKeys.cuesheetMode,
|
||||||
<div className={style.inline}>
|
defaultValue: AppMode.Edit,
|
||||||
<ViewSettings />
|
});
|
||||||
<ColumnSettings
|
|
||||||
columns={columns}
|
|
||||||
handleResetResizing={handleResetResizing}
|
|
||||||
handleResetReordering={handleResetReordering}
|
|
||||||
handleClearToggles={handleClearToggles}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={style.inline}>
|
const toggleCuesheetMode = (mode: AppMode[]) => {
|
||||||
<ViewSettingsFollowButton />
|
// we need to stop user from deselecting a mode
|
||||||
<Editor.Separator orientation='vertical' />
|
const newValue = mode.at(0);
|
||||||
<CuesheetShareModal />
|
if (!newValue) return;
|
||||||
</div>
|
setCuesheetMode(newValue);
|
||||||
</div>
|
};
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ViewSettingsFollowButton() {
|
|
||||||
const followPlayback = usePersistedCuesheetOptions((state) => state.followPlayback);
|
|
||||||
const toggle = usePersistedCuesheetOptions((state) => state.toggleOption);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button variant={followPlayback ? 'primary' : 'subtle'} onClick={() => toggle('followPlayback')}>
|
<Toolbar.Root className={style.tableSettings}>
|
||||||
<IoLocate />
|
<ViewSettings />
|
||||||
{followPlayback ? 'Following playback' : 'Follow playback'}
|
<ColumnSettings
|
||||||
</Button>
|
columns={columns}
|
||||||
|
handleResetResizing={handleResetResizing}
|
||||||
|
handleResetReordering={handleResetReordering}
|
||||||
|
handleClearToggles={handleClearToggles}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ToggleGroup value={[cuesheetMode]} onValueChange={toggleCuesheetMode} className={cx([style.group, style.apart])}>
|
||||||
|
<Toolbar.Button render={<Toggle />} value={AppMode.Run} className={style.radioButton}>
|
||||||
|
Run
|
||||||
|
</Toolbar.Button>
|
||||||
|
<Toolbar.Button render={<Toggle />} value={AppMode.Edit} className={style.radioButton}>
|
||||||
|
Edit
|
||||||
|
</Toolbar.Button>
|
||||||
|
</ToggleGroup>
|
||||||
|
|
||||||
|
<Editor.Separator orientation='vertical' />
|
||||||
|
<CuesheetShareModal />
|
||||||
|
</Toolbar.Root>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,59 +78,60 @@ function ViewSettings() {
|
|||||||
<Popover.Root>
|
<Popover.Root>
|
||||||
<Popover.Trigger
|
<Popover.Trigger
|
||||||
render={
|
render={
|
||||||
<Button variant='ghosted-white'>
|
<Toolbar.Button
|
||||||
<IoSettingsOutline /> Settings
|
render={
|
||||||
<IoChevronDown />
|
<Button variant='ghosted-white'>
|
||||||
</Button>
|
<IoSettingsOutline /> Settings
|
||||||
|
<IoChevronDown />
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<PopoverContents align='start' className={style.column}>
|
<PopoverContents align='start' className={style.inline}>
|
||||||
<Editor.Label className={style.sectionTitle}>Element visibility</Editor.Label>
|
<div className={style.column}>
|
||||||
<Editor.Label className={style.option}>
|
<Editor.Label className={style.sectionTitle}>Element visibility</Editor.Label>
|
||||||
<Checkbox
|
<Editor.Label className={style.option}>
|
||||||
defaultChecked={options.showActionMenu}
|
<Checkbox
|
||||||
onCheckedChange={(checked) => options.setOption('showActionMenu', checked)}
|
defaultChecked={options.hideTableSeconds}
|
||||||
/>
|
onCheckedChange={(checked) => options.setOption('hideTableSeconds', checked)}
|
||||||
Show action menu
|
/>
|
||||||
</Editor.Label>
|
Hide seconds in table
|
||||||
<Editor.Label className={style.option}>
|
</Editor.Label>
|
||||||
<Checkbox
|
<Editor.Label className={style.option}>
|
||||||
defaultChecked={options.hideTableSeconds}
|
<Checkbox
|
||||||
onCheckedChange={(checked) => options.setOption('hideTableSeconds', checked)}
|
defaultChecked={options.hidePast}
|
||||||
/>
|
onCheckedChange={(checked) => options.setOption('hidePast', checked)}
|
||||||
Hide seconds in table
|
/>
|
||||||
</Editor.Label>
|
Hide past events
|
||||||
<Editor.Label className={style.option}>
|
</Editor.Label>
|
||||||
<Checkbox
|
<Editor.Label className={style.option}>
|
||||||
defaultChecked={options.hidePast}
|
<Checkbox
|
||||||
onCheckedChange={(checked) => options.setOption('hidePast', checked)}
|
defaultChecked={options.hideIndexColumn}
|
||||||
/>
|
onCheckedChange={(checked) => options.setOption('hideIndexColumn', checked)}
|
||||||
Hide past events
|
/>
|
||||||
</Editor.Label>
|
Hide index column
|
||||||
<Editor.Label className={style.option}>
|
</Editor.Label>
|
||||||
<Checkbox
|
</div>
|
||||||
defaultChecked={options.hideIndexColumn}
|
|
||||||
onCheckedChange={(checked) => options.setOption('hideIndexColumn', checked)}
|
|
||||||
/>
|
|
||||||
Hide index column
|
|
||||||
</Editor.Label>
|
|
||||||
|
|
||||||
<Editor.Label className={style.sectionTitle}>Table Behaviour</Editor.Label>
|
<div className={style.column}>
|
||||||
<Editor.Label className={style.option}>
|
<Editor.Label className={style.sectionTitle}>Table Behaviour</Editor.Label>
|
||||||
<Checkbox
|
<Editor.Label className={style.option}>
|
||||||
defaultChecked={options.showDelayedTimes}
|
<Checkbox
|
||||||
onCheckedChange={(checked) => options.setOption('showDelayedTimes', checked)}
|
defaultChecked={options.showDelayedTimes}
|
||||||
/>
|
onCheckedChange={(checked) => options.setOption('showDelayedTimes', checked)}
|
||||||
Show delayed times
|
/>
|
||||||
</Editor.Label>
|
Show delayed times
|
||||||
<Editor.Label className={style.option}>
|
</Editor.Label>
|
||||||
<Checkbox
|
<Editor.Label className={style.option}>
|
||||||
defaultChecked={options.hideDelays}
|
<Checkbox
|
||||||
onCheckedChange={(checked) => options.setOption('hideDelays', checked)}
|
defaultChecked={options.hideDelays}
|
||||||
/>
|
onCheckedChange={(checked) => options.setOption('hideDelays', checked)}
|
||||||
Hide delay entries
|
/>
|
||||||
</Editor.Label>
|
Hide delay entries
|
||||||
|
</Editor.Label>
|
||||||
|
</div>
|
||||||
</PopoverContents>
|
</PopoverContents>
|
||||||
</Popover.Root>
|
</Popover.Root>
|
||||||
);
|
);
|
||||||
@@ -136,10 +147,14 @@ function ColumnSettings({
|
|||||||
<Popover.Root>
|
<Popover.Root>
|
||||||
<Popover.Trigger
|
<Popover.Trigger
|
||||||
render={
|
render={
|
||||||
<Button variant='ghosted-white'>
|
<Toolbar.Button
|
||||||
<IoOptions /> View
|
render={
|
||||||
<IoChevronDown />
|
<Button variant='ghosted-white'>
|
||||||
</Button>
|
<IoOptions /> View
|
||||||
|
<IoChevronDown />
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<PopoverContents align='start' className={style.inline}>
|
<PopoverContents align='start' className={style.inline}>
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ import { create } from 'zustand';
|
|||||||
import { persist } from 'zustand/middleware';
|
import { persist } from 'zustand/middleware';
|
||||||
|
|
||||||
type OptionValues = {
|
type OptionValues = {
|
||||||
showActionMenu: boolean;
|
|
||||||
hideTableSeconds: boolean;
|
hideTableSeconds: boolean;
|
||||||
followPlayback: boolean;
|
|
||||||
hidePast: boolean;
|
hidePast: boolean;
|
||||||
hideIndexColumn: boolean;
|
hideIndexColumn: boolean;
|
||||||
showDelayedTimes: boolean;
|
showDelayedTimes: boolean;
|
||||||
@@ -12,9 +10,7 @@ type OptionValues = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const defaultOptions: OptionValues = {
|
const defaultOptions: OptionValues = {
|
||||||
showActionMenu: false,
|
|
||||||
hideTableSeconds: false,
|
hideTableSeconds: false,
|
||||||
followPlayback: false,
|
|
||||||
hidePast: false,
|
hidePast: false,
|
||||||
hideIndexColumn: false,
|
hideIndexColumn: false,
|
||||||
showDelayedTimes: false,
|
showDelayedTimes: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user