196 lines
5.8 KiB
TypeScript

/**
* ConstructorMenu Component
*
* Draggable menu panel with actions for adding elements, backgrounds, etc.
*/
import React, { forwardRef } from 'react';
import BaseIcon from '../BaseIcon';
import BaseButton from '../BaseButton';
import {
mdiMenu,
mdiImageMultiple,
mdiViewCarousel,
mdiTooltipText,
mdiSwapHorizontal,
mdiText,
mdiPlus,
mdiExitToApp,
} from '@mdi/js';
import MenuActionButton from './MenuActionButton';
import dataFormatter from '../../helpers/dataFormatter';
import type {
Position,
CanvasElementType,
NavigationElementType,
} from './types';
import type { EditorMenuItem } from '../../types/constructor';
interface ConstructorMenuProps {
position: Position;
isOpen: boolean;
allowedNavigationTypes: NavigationElementType[];
isCreatingPage: boolean;
isSaving: boolean;
isSavingToStage: boolean;
onDragStart: (event: React.MouseEvent) => void;
onToggleOpen: () => void;
onSelectMenuItem: (item: EditorMenuItem) => void;
onAddElement: (type: CanvasElementType) => void;
onCreatePage: () => void;
onSave: () => void;
onSaveToStage: () => void;
onExit: () => void;
/** Page's last saved timestamp (updatedAt from tour_pages) */
lastSavedAt?: string | null;
/** Last save-to-stage timestamp */
lastSavedToStageAt?: string | null;
}
const ConstructorMenu = forwardRef<HTMLDivElement, ConstructorMenuProps>(
(
{
position,
isOpen,
allowedNavigationTypes,
isCreatingPage,
isSaving,
isSavingToStage,
onDragStart,
onToggleOpen,
onSelectMenuItem,
onAddElement,
onCreatePage,
onSave,
onSaveToStage,
onExit,
lastSavedAt,
lastSavedToStageAt,
},
ref,
) => {
return (
<div
ref={ref}
className='fixed z-[1000] w-60 border border-gray-200 rounded-lg bg-white shadow-xl'
style={{ left: position.x, top: position.y }}
>
<div
className='flex items-center justify-between px-3 py-2 border-b border-gray-200 cursor-move bg-gray-50 rounded-t-lg'
onMouseDown={onDragStart}
>
<span className='text-xs font-bold uppercase'>Constructor Menu</span>
<button type='button' onClick={onToggleOpen}>
<BaseIcon path={mdiMenu} size={18} />
</button>
</div>
{isOpen && (
<div className='p-2 space-y-1 max-h-[calc(100vh-120px)] overflow-y-auto'>
<MenuActionButton
icon={mdiImageMultiple}
label='Background Image'
onClick={() => onSelectMenuItem('background_image')}
/>
<MenuActionButton
icon={mdiViewCarousel}
label='Background Video'
onClick={() => onSelectMenuItem('background_video')}
/>
<MenuActionButton
icon={mdiTooltipText}
label='Background Audio'
onClick={() => onSelectMenuItem('background_audio')}
/>
<MenuActionButton
icon={mdiSwapHorizontal}
label='Add Navigation Button'
onClick={() => onAddElement(allowedNavigationTypes[0])}
/>
<MenuActionButton
icon={mdiSwapHorizontal}
label='Add Transition'
onClick={() => onSelectMenuItem('create_transition')}
/>
<MenuActionButton
icon={mdiImageMultiple}
label='Add Gallery'
onClick={() => onAddElement('gallery')}
/>
<MenuActionButton
icon={mdiViewCarousel}
label='Add Carousel'
onClick={() => onAddElement('carousel')}
/>
<MenuActionButton
icon={mdiTooltipText}
label='Add Tooltip'
onClick={() => onAddElement('tooltip')}
/>
<MenuActionButton
icon={mdiText}
label='Add Description'
onClick={() => onAddElement('description')}
/>
<MenuActionButton
icon={mdiViewCarousel}
label='Add Video Player'
onClick={() => onAddElement('video_player')}
/>
<MenuActionButton
icon={mdiTooltipText}
label='Add Audio Player'
onClick={() => onAddElement('audio_player')}
/>
<MenuActionButton
icon={mdiPlus}
label={isCreatingPage ? 'Creating Page...' : 'Create New Page'}
onClick={onCreatePage}
disabled={isCreatingPage}
/>
<div className='pt-2 border-t border-gray-200 space-y-1'>
<BaseButton
small
color='info'
label={isSaving ? 'Saving...' : 'Save'}
subtitle={
lastSavedAt
? dataFormatter.relativeTimestamp(lastSavedAt)
: undefined
}
onClick={onSave}
disabled={isSaving}
className='w-full'
/>
<BaseButton
small
color='success'
label={isSavingToStage ? 'Saving...' : 'Save to Stage'}
subtitle={
lastSavedToStageAt
? dataFormatter.relativeTimestamp(lastSavedToStageAt)
: undefined
}
onClick={onSaveToStage}
disabled={isSavingToStage}
className='w-full'
/>
<MenuActionButton
icon={mdiExitToApp}
label='Exit'
onClick={onExit}
className='!text-red-700'
/>
</div>
</div>
)}
</div>
);
},
);
ConstructorMenu.displayName = 'ConstructorMenu';
export default ConstructorMenu;