'use client' import { useViewer } from '@pascal-app/viewer' import { motion } from 'motion/react' import { TooltipProvider } from './../../../components/ui/primitives/tooltip' import { useIsMobile } from './../../../hooks/use-mobile' import { useReducedMotion } from './../../../hooks/use-reduced-motion' import { cn } from './../../../lib/utils' import useEditor from './../../../store/use-editor' import { CameraActions } from './camera-actions' import { ControlModes } from './control-modes' import { GridSnapControl, SecondaryToggles } from './view-toggles' // Mobile bottom offset matches the viewer's overlap behind the sheet's // rounded corners (SHEET_OVERLAP_PX in editor-layout-mobile) so the menu sits // just above that strip instead of inside it. const MOBILE_BOTTOM_OFFSET = 24 export function ActionMenu({ className }: { className?: string }) { const isMobile = useIsMobile() const hasSelectionOnMobile = useViewer((s) => isMobile && s.selection.selectedIds.length > 0) const hasReferenceOnMobile = useEditor((s) => isMobile && Boolean(s.selectedReferenceId)) const CONTEXTUAL_TABS = new Set(['ai', 'items', 'studio']) const isContextualPanelOnMobile = useEditor( (s) => isMobile && CONTEXTUAL_TABS.has(s.activeSidebarPanel), ) const reducedMotion = useReducedMotion() // On mobile, defer the bottom rail to the selection bar when something // is selected — the contextual actions take priority over mode controls. // Also hide on Chat / Items / Studio tabs; those are contextual workflows // (composing / picking furniture / generating renders) where the build // menu is irrelevant. if (hasSelectionOnMobile || hasReferenceOnMobile || isContextualPanelOnMobile) return null const transition = reducedMotion ? { duration: 0 } : { type: 'spring' as const, bounce: 0.2, duration: 0.4 } return ( {isMobile ? (
{/* Row 1: control modes only */}
{/* Row 2: grid snap + secondary toggles (orbit + top view hidden) */}
) : (
)} ) }