import { useRef, useEffect, 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 { isTauri } from './lib/isTauri' import { useLoaderData } from 'react-router-dom' import { IndexLoaderData } from './Router' import { useGlobalStateContext } from 'hooks/useGlobalStateContext' import { onboardingPaths } from 'routes/Onboarding' import { cameraMouseDragGuards } from 'lib/cameraControls' import { CameraDragInteractionType_type } from '@kittycad/lib/dist/types/src/models' import { CodeMenu } from 'components/CodeMenu' import { TextEditor } from 'components/TextEditor' import { Themes, getSystemTheme } from 'lib/theme' import { useSetupEngineManager } from 'hooks/useSetupEngineManager' import { useEngineConnectionSubscriptions } from 'hooks/useEngineConnectionSubscriptions' export function App() { const { code: loadedCode, project } = useLoaderData() as IndexLoaderData const streamRef = useRef(null) useHotKeyListener() const { setCode, engineCommandManager, buttonDownInStream, openPanes, setOpenPanes, didDragInStream, streamDimensions, guiMode, setGuiMode, executeAst, } = useStore((s) => ({ guiMode: s.guiMode, setGuiMode: s.setGuiMode, setCode: s.setCode, engineCommandManager: s.engineCommandManager, buttonDownInStream: s.buttonDownInStream, openPanes: s.openPanes, setOpenPanes: s.setOpenPanes, didDragInStream: s.didDragInStream, streamDimensions: s.streamDimensions, executeAst: s.executeAst, })) const { auth: { context: { token }, }, settings: { context: { showDebugPanel, onboardingStatus, cameraControls, theme }, }, } = useGlobalStateContext() 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', () => { if (guiMode.mode === 'sketch') { if (guiMode.sketchMode === 'selectFace') return if (guiMode.sketchMode === 'sketchEdit') { // TODO: share this with Toolbar's "Exit sketch" button // exiting sketch should be done consistently across all exits engineCommandManager?.sendSceneCommand({ type: 'modeling_cmd_req', cmd_id: uuidv4(), cmd: { type: 'edit_mode_exit' }, }) engineCommandManager?.sendSceneCommand({ type: 'modeling_cmd_req', cmd_id: uuidv4(), cmd: { type: 'default_camera_disable_sketch_mode' }, }) setGuiMode({ mode: 'default' }) // this is necessary to get the UI back into a consistent // state right now, hopefully won't need to rerender // when exiting sketch mode in the future executeAst() } else { engineCommandManager?.sendSceneCommand({ type: 'modeling_cmd_req', cmd_id: uuidv4(), cmd: { type: 'set_tool', tool: 'select', }, }) setGuiMode({ mode: 'sketch', sketchMode: 'sketchEdit', rotation: guiMode.rotation, position: guiMode.position, pathToNode: guiMode.pathToNode, pathId: guiMode.pathId, // todo: ...guiMod is adding isTooltip: true, will probably just fix with xstate migtaion }) } } else { setGuiMode({ mode: 'default' }) } }) const paneOpacity = [onboardingPaths.CAMERA, onboardingPaths.STREAMING].some( (p) => p === onboardingStatus ) ? 'opacity-20' : didDragInStream ? 'opacity-40' : '' // Use file code loaded from disk // on mount, and overwrite any locally-stored code useEffect(() => { if (isTauri() && loadedCode !== null) { setCode(loadedCode) } return () => { // Clear code on unmount if in desktop app if (isTauri()) { setCode('') } } }, [loadedCode, setCode]) useSetupEngineManager(streamRef, token) useEngineConnectionSubscriptions() const debounceSocketSend = throttle((message) => { engineCommandManager?.sendSceneCommand(message) }, 16) const handleMouseMove: MouseEventHandler = (e) => { e.nativeEvent.preventDefault() const { x, y } = getNormalisedCoordinates({ clientX: e.clientX, clientY: e.clientY, el: e.currentTarget, ...streamDimensions, }) const newCmdId = uuidv4() if (buttonDownInStream === undefined) { if ( guiMode.mode === 'sketch' && guiMode.sketchMode === ('sketch_line' as any) ) { debounceSocketSend({ type: 'modeling_cmd_req', cmd_id: newCmdId, cmd: { type: 'mouse_move', window: { x, y }, }, }) } else { debounceSocketSend({ type: 'modeling_cmd_req', cmd: { type: 'highlight_set_entity', selected_at_window: { x, y }, }, cmd_id: newCmdId, }) } } else { if (guiMode.mode === 'sketch' && guiMode.sketchMode === ('move' as any)) { debounceSocketSend({ type: 'modeling_cmd_req', cmd_id: newCmdId, cmd: { type: 'handle_mouse_drag_move', window: { x, y }, }, }) return } const interactionGuards = cameraMouseDragGuards[cameraControls] let interaction: CameraDragInteractionType_type const eWithButton = { ...e, button: buttonDownInStream } if (interactionGuards.pan.callback(eWithButton)) { interaction = 'pan' } else if (interactionGuards.rotate.callback(eWithButton)) { interaction = 'rotate' } else if (interactionGuards.zoom.dragCallback(eWithButton)) { interaction = 'zoom' } else { console.log('none') return } debounceSocketSend({ type: 'modeling_cmd_req', cmd: { type: 'camera_drag_move', interaction, window: { x, y }, }, cmd_id: newCmdId, }) } } return (
} >
{showDebugPanel && ( )}
) }