/** * ConstructorToolbar Component * * Unified toolbar combining page controls and element actions. * Glassmorphism styling with draggable positioning. */ import React, { useState, useRef, useEffect, forwardRef } from 'react'; import { mdiDotsVertical, mdiChevronDown, mdiImageMultiple, mdiViewCarousel, mdiTooltipText, mdiSwapHorizontal, mdiText, mdiPlus, mdiExitToApp, mdiChevronLeft, mdiChevronRight, mdiMusicNote, mdiVideo, } from '@mdi/js'; import BaseIcon from '../BaseIcon'; import BaseButton from '../BaseButton'; import ClickOutside from '../ClickOutside'; import PageSelector from './PageSelector'; import InteractionModeToggle from './InteractionModeToggle'; import MenuActionButton from './MenuActionButton'; import dataFormatter from '../../helpers/dataFormatter'; import type { ConstructorToolbarProps } from './types'; const ConstructorToolbar = forwardRef( ( { position, onDragStart, pages, activePageId, onPageChange, interactionMode, onModeChange, onSelectMenuItem, allowedNavigationTypes, onAddElement, onCreatePage, isCreatingPage, onSave, onSaveToStage, isSaving, isSavingToStage, lastSavedAt, lastSavedToStageAt, onExit, }, ref, ) => { // Local UI state const [isCollapsed, setIsCollapsed] = useState(false); const [activeDropdown, setActiveDropdown] = useState< 'bg' | 'elements' | null >(null); // Refs for ClickOutside exclusion (following NavBarItem pattern) const bgTriggerRef = useRef(null); const elementsTriggerRef = useRef(null); // Keyboard handling (Escape closes dropdown) useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape' && activeDropdown) { setActiveDropdown(null); } }; document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); }, [activeDropdown]); // Dropdown handlers const closeDropdown = () => setActiveDropdown(null); const toggleDropdown = (dropdown: 'bg' | 'elements') => { setActiveDropdown((prev) => (prev === dropdown ? null : dropdown)); }; // Close dropdown after menu action const handleMenuAction = (action: () => void) => { action(); closeDropdown(); }; // Shared button styles const triggerBtnClass = 'flex items-center gap-1.5 px-3 py-2 rounded text-sm font-medium text-white/90 hover:bg-white/20 transition-colors'; const dropdownPanelClass = 'absolute top-full left-0 mt-1 min-w-[180px] py-1 rounded-lg bg-white/50 backdrop-blur-xl border border-white/30 shadow-lg z-10'; // Collapsed state if (isCollapsed) { return (
{pages.find((p) => p.id === activePageId)?.name || 'Page'}
); } return (
{/* Drag Handle */}
{/* Page Selector - reuse existing component */} {/* Mode Toggle - reuse with compact=true */} {/* Divider */}
{/* Backgrounds Dropdown */}
{activeDropdown === 'bg' && (
handleMenuAction(() => onSelectMenuItem('background_image')) } /> handleMenuAction(() => onSelectMenuItem('background_video')) } /> handleMenuAction(() => onSelectMenuItem('background_audio')) } />
)}
{/* Elements Dropdown */}
{activeDropdown === 'elements' && (
handleMenuAction(() => onAddElement(allowedNavigationTypes[0]), ) } /> handleMenuAction(() => onSelectMenuItem('create_transition'), ) } /> handleMenuAction(() => onAddElement('gallery')) } /> handleMenuAction(() => onAddElement('carousel')) } /> handleMenuAction(() => onAddElement('tooltip')) } /> handleMenuAction(() => onAddElement('description')) } /> handleMenuAction(() => onAddElement('video_player')) } /> handleMenuAction(() => onAddElement('audio_player')) } />
)}
{/* Divider */}
{/* Create Page Button */} {/* Save Button - reuse BaseButton with subtitle */} {/* Save to Stage Button */} {/* Exit Button */} {/* Collapse Toggle */}
); }, ); ConstructorToolbar.displayName = 'ConstructorToolbar'; export default ConstructorToolbar;