-
- {sortProject(fileContext.project?.children || []).map((fileOrDir) => (
- {
- // Reset modeling state when navigating to a new file
- modelingSend({ type: 'Cancel' })
- onNavigateToFile?.()
- }}
- key={fileOrDir.path}
- />
- ))}
-
+
+
+
+ {showNewTreeEntry && (
+
+
+
+
+ )}
+ {sortFilesAndDirectories(fileContext.project?.children || []).map(
+ (fileOrDir) => (
+
+ )
+ )}
+
+
)
}
diff --git a/src/components/LowerRightControls.tsx b/src/components/LowerRightControls.tsx
index ad3ddb8082..41531ef42f 100644
--- a/src/components/LowerRightControls.tsx
+++ b/src/components/LowerRightControls.tsx
@@ -96,6 +96,23 @@ export function LowerRightControls({
Report a bug
+
+
+
Telemetry
+
+ Telemetry
+
+
{
editorManager.setCopilotEnabled(true)
},
- 'sketch exit execute': ({ context: { store } }) => {
- ;(async () => {
- // When cancelling the sketch mode we should disable sketch mode within the engine.
- await engineCommandManager.sendSceneCommand({
- type: 'modeling_cmd_req',
- cmd_id: uuidv4(),
- cmd: { type: 'sketch_mode_disable' },
- })
+ // tsc reports this typing as perfectly fine, but eslint is complaining.
+ // It's actually nonsensical, so I'm quieting.
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
+ 'sketch exit execute': async ({
+ context: { store },
+ }): Promise
=> {
+ // When cancelling the sketch mode we should disable sketch mode within the engine.
+ await engineCommandManager.sendSceneCommand({
+ type: 'modeling_cmd_req',
+ cmd_id: uuidv4(),
+ cmd: { type: 'sketch_mode_disable' },
+ })
- sceneInfra.camControls.syncDirection = 'clientToEngine'
+ sceneInfra.camControls.syncDirection = 'clientToEngine'
- if (cameraProjection.current === 'perspective') {
- await sceneInfra.camControls.snapToPerspectiveBeforeHandingBackControlToEngine()
- }
+ if (cameraProjection.current === 'perspective') {
+ await sceneInfra.camControls.snapToPerspectiveBeforeHandingBackControlToEngine()
+ }
- sceneInfra.camControls.syncDirection = 'engineToClient'
+ sceneInfra.camControls.syncDirection = 'engineToClient'
- store.videoElement?.pause()
+ store.videoElement?.pause()
- kclManager
- .executeCode()
- .then(() => {
- if (engineCommandManager.engineConnection?.idleMode) return
+ return kclManager
+ .executeCode()
+ .then(() => {
+ if (engineCommandManager.engineConnection?.idleMode) return
- store.videoElement?.play().catch((e) => {
- console.warn('Video playing was prevented', e)
- })
+ store.videoElement?.play().catch((e) => {
+ console.warn('Video playing was prevented', e)
})
- .catch(reportRejection)
- })().catch(reportRejection)
+ })
+ .catch(reportRejection)
},
'Set mouse state': assign(({ context, event }) => {
if (event.type !== 'Set mouse state') return {}
diff --git a/src/components/ModelingSidebar/ModelingPane.tsx b/src/components/ModelingSidebar/ModelingPane.tsx
index a5ffc079f5..2f959b4192 100644
--- a/src/components/ModelingSidebar/ModelingPane.tsx
+++ b/src/components/ModelingSidebar/ModelingPane.tsx
@@ -48,7 +48,7 @@ export const ModelingPaneHeader = ({
bgClassName: 'bg-transparent dark:bg-transparent',
}}
className="!p-0 !bg-transparent hover:text-primary border-transparent dark:!border-transparent hover:!border-primary dark:hover:!border-chalkboard-70 !outline-none"
- onClick={onClose}
+ onClick={() => onClose()}
>
Close
@@ -59,14 +59,12 @@ export const ModelingPaneHeader = ({
}
export const ModelingPane = ({
- title,
- icon,
id,
children,
className,
- Menu,
detailsTestId,
onClose,
+ title,
...props
}: ModelingPaneProps) => {
const { settings } = useSettingsAuthContext()
@@ -78,6 +76,7 @@ export const ModelingPane = ({
return (
-
- {children}
+ {children}
)
}
diff --git a/src/components/ModelingSidebar/ModelingPanes/DebugPane.tsx b/src/components/ModelingSidebar/ModelingPanes/DebugPane.tsx
index f96cb9ef69..c98810ded6 100644
--- a/src/components/ModelingSidebar/ModelingPanes/DebugPane.tsx
+++ b/src/components/ModelingSidebar/ModelingPanes/DebugPane.tsx
@@ -5,16 +5,18 @@ import { CamDebugSettings } from 'clientSideScene/ClientSideSceneComp'
export const DebugPane = () => {
return (
-
+
)
}
diff --git a/src/components/ModelingSidebar/ModelingPanes/KclEditorPane.tsx b/src/components/ModelingSidebar/ModelingPanes/KclEditorPane.tsx
index f27f412267..e43132958d 100644
--- a/src/components/ModelingSidebar/ModelingPanes/KclEditorPane.tsx
+++ b/src/components/ModelingSidebar/ModelingPanes/KclEditorPane.tsx
@@ -4,7 +4,7 @@ import { Themes, getSystemTheme } from 'lib/theme'
import { useMemo, useRef } from 'react'
import { highlightSelectionMatches, searchKeymap } from '@codemirror/search'
import { lineHighlightField } from 'editor/highlightextension'
-import { roundOff } from 'lib/utils'
+import { onMouseDragMakeANewNumber, onMouseDragRegex } from 'lib/utils'
import {
lineNumbers,
rectangularSelection,
@@ -129,7 +129,9 @@ export const KclEditorPane = () => {
closeBrackets(),
highlightActiveLine(),
highlightSelectionMatches(),
- syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
+ syntaxHighlighting(defaultHighlightStyle, {
+ fallback: true,
+ }),
rectangularSelection(),
dropCursor(),
interact({
@@ -137,29 +139,12 @@ export const KclEditorPane = () => {
// a rule for a number dragger
{
// the regexp matching the value
- regexp: /-?\b\d+\.?\d*\b/g,
+ regexp: onMouseDragRegex,
// set cursor to "ew-resize" on hover
cursor: 'ew-resize',
// change number value based on mouse X movement on drag
onDrag: (text, setText, e) => {
- const multiplier =
- e.shiftKey && e.metaKey
- ? 0.01
- : e.metaKey
- ? 0.1
- : e.shiftKey
- ? 10
- : 1
-
- const delta = e.movementX * multiplier
-
- const newVal = roundOff(
- Number(text) + delta,
- multiplier === 0.01 ? 2 : multiplier === 0.1 ? 1 : 0
- )
-
- if (isNaN(newVal)) return
- setText(newVal.toString())
+ onMouseDragMakeANewNumber(text, setText, e)
},
},
],
@@ -174,27 +159,31 @@ export const KclEditorPane = () => {
const initialCode = useRef(codeManager.code)
return (
-
-
{
- if (_editorView === null) return
+
+
+ {
+ if (_editorView === null) return
- editorManager.setEditorView(_editorView)
+ editorManager.setEditorView(_editorView)
- // On first load of this component, ensure we show the current errors
- // in the editor.
- // Make sure we don't add them twice.
- if (diagnosticCount(_editorView.state) === 0) {
- kclManager.setDiagnosticsForCurrentErrors()
- }
- }}
- />
+ // On first load of this component, ensure we show the current errors
+ // in the editor.
+ // Make sure we don't add them twice.
+ if (diagnosticCount(_editorView.state) === 0) {
+ kclManager.setDiagnosticsForCurrentErrors()
+ }
+ }}
+ />
+
)
}
diff --git a/src/components/ModelingSidebar/ModelingPanes/MemoryPane.test.tsx b/src/components/ModelingSidebar/ModelingPanes/MemoryPane.test.tsx
index 6b1931875e..6b3adfbb2e 100644
--- a/src/components/ModelingSidebar/ModelingPanes/MemoryPane.test.tsx
+++ b/src/components/ModelingSidebar/ModelingPanes/MemoryPane.test.tsx
@@ -43,14 +43,14 @@ describe('processMemory', () => {
tag: null,
id: expect.any(String),
faceId: expect.any(String),
- sourceRange: [170, 194],
+ sourceRange: [170, 194, 0],
},
{
type: 'extrudePlane',
tag: null,
id: expect.any(String),
faceId: expect.any(String),
- sourceRange: [202, 230],
+ sourceRange: [202, 230, 0],
},
],
theSketch: [
diff --git a/src/components/ModelingSidebar/ModelingPanes/index.tsx b/src/components/ModelingSidebar/ModelingPanes/index.tsx
index f48c16b0ca..3284275343 100644
--- a/src/components/ModelingSidebar/ModelingPanes/index.tsx
+++ b/src/components/ModelingSidebar/ModelingPanes/index.tsx
@@ -2,11 +2,17 @@ import { IconDefinition, faBugSlash } from '@fortawesome/free-solid-svg-icons'
import { KclEditorMenu } from 'components/ModelingSidebar/ModelingPanes/KclEditorMenu'
import { CustomIconName } from 'components/CustomIcon'
import { KclEditorPane } from 'components/ModelingSidebar/ModelingPanes/KclEditorPane'
+import { ModelingPaneHeader } from 'components/ModelingSidebar/ModelingPane'
import { MouseEventHandler, ReactNode } from 'react'
import { MemoryPane, MemoryPaneMenu } from './MemoryPane'
import { LogsPane } from './LoggingPanes'
import { DebugPane } from './DebugPane'
-import { FileTreeInner, FileTreeMenu, FileTreeRoot } from 'components/FileTree'
+import {
+ FileTreeInner,
+ FileTreeMenu,
+ FileTreeRoot,
+ useFileTreeOperations,
+} from 'components/FileTree'
import { useKclContext } from 'lang/KclProvider'
import { editorManager } from 'lib/singletons'
import { ContextFrom } from 'xstate'
@@ -38,20 +44,19 @@ interface PaneCallbackProps {
export type SidebarPane = {
id: SidebarType
- title: ReactNode
- sidebarName?: string
+ sidebarName: string
icon: CustomIconName | IconDefinition
keybinding: string
- Content: ReactNode | React.FC
- Menu?: ReactNode | React.FC
+ Content: React.FC<{ id: SidebarType; onClose: () => void }>
hide?: boolean | ((props: PaneCallbackProps) => boolean)
showBadge?: BadgeInfo
}
export type SidebarAction = {
id: string
- title: ReactNode
+ sidebarName: string
icon: CustomIconName
+ title: ReactNode
iconClassName?: string // Just until we get rid of FontAwesome icons
keybinding: string
action: () => void
@@ -59,14 +64,30 @@ export type SidebarAction = {
disable?: () => string | undefined
}
+// For now a lot of icons are the same but the reality is they could totally
+// be different, like an icon based on some data for the pane, or the icon
+// changes to be a spinning loader on loading.
+
export const sidebarPanes: SidebarPane[] = [
{
id: 'code',
- title: 'KCL Code',
icon: 'code',
- Content: KclEditorPane,
+ sidebarName: 'KCL Code',
+ Content: (props: { id: SidebarType; onClose: () => void }) => {
+ return (
+ <>
+ }
+ onClose={props.onClose}
+ />
+
+ >
+ )
+ },
keybinding: 'Shift + C',
- Menu: KclEditorMenu,
showBadge: {
value: ({ kclContext }) => {
return kclContext.errors.length
@@ -79,34 +100,96 @@ export const sidebarPanes: SidebarPane[] = [
},
{
id: 'files',
- title: ,
- sidebarName: 'Project Files',
icon: 'folder',
- Content: FileTreeInner,
+ sidebarName: 'Project Files',
+ Content: (props: { id: SidebarType; onClose: () => void }) => {
+ const { createFile, createFolder, newTreeEntry } = useFileTreeOperations()
+
+ return (
+ <>
+ }
+ Menu={
+ createFile({ dryRun: true })}
+ onCreateFolder={() => createFolder({ dryRun: true })}
+ />
+ }
+ onClose={props.onClose}
+ />
+ createFile({ dryRun: false, name })}
+ onCreateFolder={(name: string) =>
+ createFolder({ dryRun: false, name })
+ }
+ newTreeEntry={newTreeEntry}
+ />
+ >
+ )
+ },
keybinding: 'Shift + F',
- Menu: FileTreeMenu,
hide: ({ platform }) => platform === 'web',
},
{
id: 'variables',
- title: 'Variables',
icon: 'make-variable',
- Content: MemoryPane,
- Menu: MemoryPaneMenu,
+ sidebarName: 'Variables',
+ Content: (props: { id: SidebarType; onClose: () => void }) => {
+ return (
+ <>
+ }
+ onClose={props.onClose}
+ />
+
+ >
+ )
+ },
keybinding: 'Shift + V',
},
{
id: 'logs',
- title: 'Logs',
icon: 'logs',
- Content: LogsPane,
+ sidebarName: 'Logs',
+ Content: (props: { id: SidebarType; onClose: () => void }) => {
+ return (
+ <>
+
+
+ >
+ )
+ },
keybinding: 'Shift + L',
},
{
id: 'debug',
- title: 'Debug',
icon: faBugSlash,
- Content: DebugPane,
+ sidebarName: 'Debug',
+ Content: (props: { id: SidebarType; onClose: () => void }) => {
+ return (
+ <>
+
+
+ >
+ )
+ },
keybinding: 'Shift + D',
hide: ({ settings }) => !settings.modeling.showDebugPanel.current,
},
diff --git a/src/components/ModelingSidebar/ModelingSidebar.module.css b/src/components/ModelingSidebar/ModelingSidebar.module.css
index c2bda853d7..e69de29bb2 100644
--- a/src/components/ModelingSidebar/ModelingSidebar.module.css
+++ b/src/components/ModelingSidebar/ModelingSidebar.module.css
@@ -1,11 +0,0 @@
-.grid {
- display: grid;
- grid-template-columns: auto 1fr;
- grid-template-rows: 1fr 1fr;
- row-gap: 0.25rem;
- align-items: stretch;
- position: relative;
- padding-block: 1px;
- max-width: 100%;
- flex: 1 1 0;
-}
diff --git a/src/components/ModelingSidebar/ModelingSidebar.tsx b/src/components/ModelingSidebar/ModelingSidebar.tsx
index 81a3ee2026..77eeca84bb 100644
--- a/src/components/ModelingSidebar/ModelingSidebar.tsx
+++ b/src/components/ModelingSidebar/ModelingSidebar.tsx
@@ -5,14 +5,12 @@ import {
useCallback,
useEffect,
useMemo,
- ReactNode,
useContext,
} from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import { SidebarAction, SidebarType, sidebarPanes } from './ModelingPanes'
import Tooltip from 'components/Tooltip'
import { ActionIcon } from 'components/ActionIcon'
-import styles from './ModelingSidebar.module.css'
import { ModelingPane } from './ModelingPane'
import { isDesktop } from 'lib/isDesktop'
import { useModelingContext } from 'hooks/useModelingContext'
@@ -62,6 +60,7 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
{
id: 'export',
title: 'Export part',
+ sidebarName: 'Export part',
icon: 'floppyDiskArrow',
keybinding: 'Ctrl + Shift + E',
action: () =>
@@ -73,6 +72,7 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
{
id: 'make',
title: 'Make part',
+ sidebarName: 'Make part',
icon: 'printer3d',
keybinding: 'Ctrl + Shift + M',
// eslint-disable-next-line @typescript-eslint/no-misused-promises
@@ -182,7 +182,7 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
bottomRight: 'hidden',
}}
>
-