import { useCallback, MouseEventHandler } from 'react' import { DebugPanel } from './components/DebugPanel' import { v4 as uuidv4 } from 'uuid' import { PaneType, useStore } from './useStore' import { Logs, KCLErrors } from './components/Logs' import { CollapsiblePanel } from './components/CollapsiblePanel' import { MemoryPanel } from './components/MemoryPanel' import { useHotKeyListener } from './hooks/useHotKeyListener' import { Stream } from './components/Stream' import ModalContainer from 'react-modal-promise' import { EngineCommand } from './lang/std/engineConnection' import { throttle } from './lib/utils' import { AppHeader } from './components/AppHeader' import { Resizable } from 're-resizable' import { faCode, faCodeCommit, faSquareRootVariable, } from '@fortawesome/free-solid-svg-icons' import { useHotkeys } from 'react-hotkeys-hook' import { getNormalisedCoordinates } from './lib/utils' import { useLoaderData, useNavigate } from 'react-router-dom' import { type IndexLoaderData } from 'lib/types' import { paths } from 'lib/paths' import { useGlobalStateContext } from 'hooks/useGlobalStateContext' import { onboardingPaths } from 'routes/Onboarding/paths' import { CodeMenu } from 'components/CodeMenu' import { TextEditor } from 'components/TextEditor' import { Themes, getSystemTheme } from 'lib/theme' import { useEngineConnectionSubscriptions } from 'hooks/useEngineConnectionSubscriptions' import { engineCommandManager } from './lang/std/engineConnection' import { useModelingContext } from 'hooks/useModelingContext' import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath' import { isTauri } from 'lib/isTauri' export function App() { const { project, file } = useLoaderData() as IndexLoaderData const navigate = useNavigate() const filePath = useAbsoluteFilePath() useHotKeyListener() const { buttonDownInStream, openPanes, setOpenPanes, didDragInStream, streamDimensions, } = useStore((s) => ({ buttonDownInStream: s.buttonDownInStream, openPanes: s.openPanes, setOpenPanes: s.setOpenPanes, didDragInStream: s.didDragInStream, streamDimensions: s.streamDimensions, })) const { settings } = useGlobalStateContext() const { showDebugPanel, onboardingStatus, theme } = settings?.context || {} const { state, send } = useModelingContext() const editorTheme = theme === Themes.System ? getSystemTheme() : theme // Pane toggling keyboard shortcuts const togglePane = useCallback( (newPane: PaneType) => openPanes.includes(newPane) ? setOpenPanes(openPanes.filter((p) => p !== newPane)) : setOpenPanes([...openPanes, newPane]), [openPanes, setOpenPanes] ) useHotkeys('shift + c', () => togglePane('code')) useHotkeys('shift + v', () => togglePane('variables')) useHotkeys('shift + l', () => togglePane('logs')) useHotkeys('shift + e', () => togglePane('kclErrors')) useHotkeys('shift + d', () => togglePane('debug')) useHotkeys('esc', () => send('Cancel')) useHotkeys( isTauri() ? 'mod + ,' : 'shift + mod + ,', () => navigate(filePath + paths.SETTINGS), { splitKey: '|', } ) const paneOpacity = [onboardingPaths.CAMERA, onboardingPaths.STREAMING].some( (p) => p === onboardingStatus ) ? 'opacity-20' : didDragInStream ? 'opacity-40' : '' useEngineConnectionSubscriptions() const debounceSocketSend = throttle((message) => { engineCommandManager.sendSceneCommand(message) }, 1000 / 15) const handleMouseMove: MouseEventHandler = (e) => { if (state.matches('Sketch')) { return } const { x, y } = getNormalisedCoordinates({ clientX: e.clientX, clientY: e.clientY, el: e.currentTarget, ...streamDimensions, }) const newCmdId = uuidv4() if (buttonDownInStream === undefined) { debounceSocketSend({ type: 'modeling_cmd_req', cmd: { type: 'highlight_set_entity', selected_at_window: { x, y }, }, cmd_id: newCmdId, }) } } return (
} >
{showDebugPanel && ( )} {/* */}
) }