Compare commits
7 Commits
main
...
franknoiro
Author | SHA1 | Date | |
---|---|---|---|
ec4fd08a7d | |||
40388b80e7 | |||
4b00d00977 | |||
fc574fa638 | |||
0bea2bcc98 | |||
a1059d547a | |||
e4b40f6d36 |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 132 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 132 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 66 KiB |
19
package-lock.json
generated
@ -26640,10 +26640,27 @@
|
||||
"vscode-uri": "^3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.14.1",
|
||||
"@types/node": "^24.0.7",
|
||||
"ts-node": "^10.9.2"
|
||||
}
|
||||
},
|
||||
"packages/codemirror-lsp-client/node_modules/@types/node": {
|
||||
"version": "24.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.10.tgz",
|
||||
"integrity": "sha512-ENHwaH+JIRTDIEEbDK6QSQntAYGtbvdDXnMXnZaZ6k13Du1dPMmprkEHIL7ok2Wl2aZevetwTAb5S+7yIF+enA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.8.0"
|
||||
}
|
||||
},
|
||||
"packages/codemirror-lsp-client/node_modules/undici-types": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
|
||||
"integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"rust/kcl-language-server": {
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
|
@ -10,4 +10,3 @@
|
||||
5) src/lang/std/sketch.ts -> src/lang/modifyAst.ts -> src/lang/std/sketchcombos.ts
|
||||
6) src/lib/singletons.ts -> src/clientSideScene/sceneEntities.ts -> src/clientSideScene/segments.ts -> src/components/Toolbar/angleLengthInfo.ts
|
||||
7) src/lib/singletons.ts -> src/clientSideScene/sceneEntities.ts -> src/clientSideScene/segments.ts
|
||||
8) src/hooks/useModelingContext.ts -> src/components/ModelingMachineProvider.tsx -> src/components/Toolbar/setAngleLength.tsx -> src/components/SetAngleLengthModal.tsx -> src/lib/useCalculateKclExpression.ts
|
||||
|
22
src/App.tsx
@ -65,6 +65,7 @@ import { useModelingContext } from '@src/hooks/useModelingContext'
|
||||
import { xStateValueToString } from '@src/lib/xStateValueToString'
|
||||
import { getSelectionTypeDisplayText } from '@src/lib/selections'
|
||||
import type { StatusBarItemType } from '@src/components/StatusBar/statusBarTypes'
|
||||
import { Toolbar } from '@src/Toolbar'
|
||||
|
||||
// CYCLIC REF
|
||||
sceneInfra.camControls.engineStreamActor = engineStreamActor
|
||||
@ -246,15 +247,18 @@ export function App() {
|
||||
return (
|
||||
<div className="h-screen flex flex-col overflow-hidden select-none">
|
||||
<div className="relative flex flex-1 flex-col">
|
||||
<AppHeader
|
||||
className="transition-opacity transition-duration-75"
|
||||
project={{ project, file }}
|
||||
enableMenu={true}
|
||||
nativeFileMenuCreated={nativeFileMenuCreated}
|
||||
>
|
||||
<CommandBarOpenButton />
|
||||
<ShareButton />
|
||||
</AppHeader>
|
||||
<div className="relative flex items-center flex-col">
|
||||
<AppHeader
|
||||
className="transition-opacity transition-duration-75"
|
||||
project={{ project, file }}
|
||||
enableMenu={true}
|
||||
nativeFileMenuCreated={nativeFileMenuCreated}
|
||||
>
|
||||
<CommandBarOpenButton />
|
||||
<ShareButton />
|
||||
</AppHeader>
|
||||
<Toolbar />
|
||||
</div>
|
||||
<ModalContainer />
|
||||
<ModelingSidebar />
|
||||
<EngineStream pool={pool} authToken={authToken} />
|
||||
|
@ -203,7 +203,7 @@ export function Toolbar({
|
||||
<menu
|
||||
data-current-mode={currentMode}
|
||||
data-onboarding-id="toolbar"
|
||||
className="max-w-full whitespace-nowrap rounded-b px-2 py-1 bg-chalkboard-10 dark:bg-chalkboard-90 relative border border-chalkboard-30 dark:border-chalkboard-80 border-t-0 shadow-sm"
|
||||
className="z-[19] max-w-full whitespace-nowrap rounded-b px-2 py-1 bg-chalkboard-10 dark:bg-chalkboard-90 relative border border-chalkboard-30 dark:border-chalkboard-80 border-t-0 shadow-sm"
|
||||
>
|
||||
<ul
|
||||
{...props}
|
||||
|
@ -3,7 +3,6 @@
|
||||
in Tailwind, such as complex grid layouts.
|
||||
*/
|
||||
.header {
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
@ -1,30 +1,30 @@
|
||||
import { Toolbar } from '@src/Toolbar'
|
||||
import { CommandBarOpenButton } from '@src/components/CommandBarOpenButton'
|
||||
import ProjectSidebarMenu from '@src/components/ProjectSidebarMenu'
|
||||
import UserSidebarMenu from '@src/components/UserSidebarMenu'
|
||||
import { isDesktop } from '@src/lib/isDesktop'
|
||||
import { type IndexLoaderData } from '@src/lib/types'
|
||||
import type { IndexLoaderData } from '@src/lib/types'
|
||||
import { useUser } from '@src/lib/singletons'
|
||||
|
||||
import styles from './AppHeader.module.css'
|
||||
import type { ReactNode } from 'react'
|
||||
|
||||
interface AppHeaderProps extends React.PropsWithChildren {
|
||||
showToolbar?: boolean
|
||||
project?: Omit<IndexLoaderData, 'code'>
|
||||
className?: string
|
||||
enableMenu?: boolean
|
||||
style?: React.CSSProperties
|
||||
nativeFileMenuCreated: boolean
|
||||
projectMenuChildren?: ReactNode
|
||||
}
|
||||
|
||||
export const AppHeader = ({
|
||||
showToolbar = true,
|
||||
project,
|
||||
children,
|
||||
className = '',
|
||||
style,
|
||||
enableMenu = false,
|
||||
nativeFileMenuCreated,
|
||||
projectMenuChildren,
|
||||
}: AppHeaderProps) => {
|
||||
const user = useUser()
|
||||
|
||||
@ -32,14 +32,9 @@ export const AppHeader = ({
|
||||
<header
|
||||
id="app-header"
|
||||
data-testid="app-header"
|
||||
className={
|
||||
'w-full grid ' +
|
||||
styles.header +
|
||||
` ${
|
||||
isDesktop() ? styles.desktopApp + ' ' : ''
|
||||
}overlaid-panes sticky top-0 z-20 px-2 items-start ` +
|
||||
className
|
||||
}
|
||||
className={`w-full flex ${styles.header || ''} ${
|
||||
isDesktop() ? styles.desktopApp : ''
|
||||
} overlaid-panes sticky top-0 z-20 px-2 justify-between ${className || ''} bg-chalkboard-10 dark:bg-chalkboard-90 border-b border-chalkboard-30 dark:border-chalkboard-70`}
|
||||
data-native-file-menu={nativeFileMenuCreated}
|
||||
style={style}
|
||||
>
|
||||
@ -47,13 +42,9 @@ export const AppHeader = ({
|
||||
enableMenu={enableMenu}
|
||||
project={project?.project}
|
||||
file={project?.file}
|
||||
/>
|
||||
{/* Toolbar if the context deems it */}
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<div className="flex-grow flex justify-center max-w-lg md:max-w-xl lg:max-w-2xl xl:max-w-4xl 2xl:max-w-5xl">
|
||||
{showToolbar && <Toolbar />}
|
||||
</div>
|
||||
</div>
|
||||
>
|
||||
{projectMenuChildren}
|
||||
</ProjectSidebarMenu>
|
||||
<div className="flex items-center gap-2 py-1 ml-auto">
|
||||
{/* If there are children, show them, otherwise show User menu */}
|
||||
{children || <CommandBarOpenButton />}
|
||||
|
@ -33,6 +33,7 @@ import { useSettings } from '@src/lib/singletons'
|
||||
import { commandBarActor, useCommandBarState } from '@src/lib/singletons'
|
||||
|
||||
import styles from './CommandBarKclInput.module.css'
|
||||
import { useModelingContext } from '@src/hooks/useModelingContext'
|
||||
|
||||
// TODO: remove the need for this selector once we decouple all actors from React
|
||||
const machineContextSelector = (snapshot?: SnapshotFrom<AnyStateMachine>) =>
|
||||
@ -55,6 +56,9 @@ function CommandBarKclInput({
|
||||
arg.name
|
||||
] as KclCommandValue | undefined
|
||||
const settings = useSettings()
|
||||
const {
|
||||
context: { selectionRanges },
|
||||
} = useModelingContext()
|
||||
const argMachineContext = useSelector(
|
||||
arg.machineActor,
|
||||
machineContextSelector
|
||||
@ -126,6 +130,7 @@ function CommandBarKclInput({
|
||||
value,
|
||||
initialVariableName,
|
||||
sourceRange: sourceRangeForPrevVariables,
|
||||
selectionRanges,
|
||||
})
|
||||
|
||||
const varMentionData: Completion[] = prevVariables.map((v) => {
|
||||
|
@ -10,13 +10,13 @@ export function CommandBarOpenButton() {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="flex gap-1 items-center py-0 px-0.5 m-0 text-primary dark:text-inherit bg-chalkboard-10/80 dark:bg-chalkboard-100/50 hover:bg-chalkboard-10 dark:hover:bg-chalkboard-100 border border-solid border-primary/50 hover:border-primary active:border-primary"
|
||||
className="flex gap-1 items-center py-0 pl-0.5 pr-1 sm:pr-0.5 m-0 text-primary dark:text-inherit bg-chalkboard-10/80 dark:bg-chalkboard-100/50 hover:bg-chalkboard-10 dark:hover:bg-chalkboard-100 border border-solid border-primary/50 hover:border-primary active:border-primary"
|
||||
onClick={() => commandBarActor.send({ type: 'Open' })}
|
||||
data-testid="command-bar-open-button"
|
||||
>
|
||||
<CustomIcon name="command" className="w-5 h-5" />
|
||||
<span>Commands</span>
|
||||
<kbd className="dark:bg-chalkboard-80 font-mono rounded-sm text-primary/70 dark:text-inherit inline-block px-1">
|
||||
<kbd className="hidden sm:block dark:bg-chalkboard-80 font-mono rounded-sm text-primary/70 dark:text-inherit inline-block px-1">
|
||||
{hotkeyDisplay(COMMAND_PALETTE_HOTKEY, platform)}
|
||||
</kbd>
|
||||
</button>
|
||||
|
@ -17,40 +17,39 @@ import { APP_NAME } from '@src/lib/constants'
|
||||
import { isDesktop } from '@src/lib/isDesktop'
|
||||
import { PATHS } from '@src/lib/paths'
|
||||
import { engineCommandManager, kclManager } from '@src/lib/singletons'
|
||||
import { type IndexLoaderData } from '@src/lib/types'
|
||||
import type { IndexLoaderData } from '@src/lib/types'
|
||||
import { commandBarActor } from '@src/lib/singletons'
|
||||
|
||||
interface ProjectSidebarMenuProps extends React.PropsWithChildren {
|
||||
enableMenu?: boolean
|
||||
project?: IndexLoaderData['project']
|
||||
file?: IndexLoaderData['file']
|
||||
}
|
||||
|
||||
const ProjectSidebarMenu = ({
|
||||
project,
|
||||
file,
|
||||
enableMenu = false,
|
||||
}: {
|
||||
enableMenu?: boolean
|
||||
project?: IndexLoaderData['project']
|
||||
file?: IndexLoaderData['file']
|
||||
}) => {
|
||||
children,
|
||||
}: ProjectSidebarMenuProps) => {
|
||||
// Make room for traffic lights on desktop left side.
|
||||
// TODO: make sure this doesn't look like shit on Linux or Windows
|
||||
const trafficLightsOffset =
|
||||
isDesktop() && window.electron.os.isMac ? 'ml-20' : ''
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
'!no-underline h-full mr-auto max-h-min min-h-12 min-w-max flex items-center gap-2 ' +
|
||||
trafficLightsOffset
|
||||
}
|
||||
>
|
||||
<div className={'!no-underline flex gap-2 ' + trafficLightsOffset}>
|
||||
<AppLogoLink project={project} file={file} />
|
||||
{enableMenu ? (
|
||||
<ProjectMenuPopover project={project} file={file} />
|
||||
) : (
|
||||
<span
|
||||
className="hidden select-none cursor-default text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block"
|
||||
className="hidden self-center px-2 select-none cursor-default text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block"
|
||||
data-testid="project-name"
|
||||
>
|
||||
{project?.name ? project.name : APP_NAME}
|
||||
</span>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -64,7 +63,7 @@ function AppLogoLink({
|
||||
}) {
|
||||
const { onProjectClose } = useLspContext()
|
||||
const wrapperClassName =
|
||||
"relative h-full grid place-content-center group p-1.5 before:block before:content-[''] before:absolute before:inset-0 before:bottom-2.5 before:z-[-1] before:bg-primary before:rounded-b-sm"
|
||||
"relative h-full grid flex-none place-content-center group p-1.5 before:block before:content-[''] before:absolute before:inset-0 before:bottom-1 before:z-[-1] before:bg-primary before:rounded-b-sm"
|
||||
const logoClassName = 'w-auto h-4 text-chalkboard-10'
|
||||
|
||||
return isDesktop() ? (
|
||||
@ -238,12 +237,23 @@ function ProjectMenuPopover({
|
||||
return (
|
||||
<Popover className="relative">
|
||||
<Popover.Button
|
||||
className="gap-1 rounded-sm h-9 mr-auto max-h-min min-w-max border-0 py-1 px-2 flex items-center focus-visible:outline-appForeground dark:hover:bg-chalkboard-90"
|
||||
className="gap-1 rounded-sm mr-auto max-h-min min-w-max border-0 py-1 px-2 flex items-center focus-visible:outline-appForeground dark:hover:bg-chalkboard-90"
|
||||
data-testid="project-sidebar-toggle"
|
||||
>
|
||||
<div className="flex flex-col items-start py-0.5">
|
||||
<div className="flex items-baseline py-0.5 text-sm gap-1">
|
||||
{isDesktop() && project?.name && (
|
||||
<>
|
||||
<span
|
||||
className="hidden whitespace-nowrap md:block"
|
||||
data-testid="app-header-project-name"
|
||||
>
|
||||
{project.name}
|
||||
</span>
|
||||
<span className="hidden md:block">/</span>
|
||||
</>
|
||||
)}
|
||||
<span
|
||||
className="hidden text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block"
|
||||
className="text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap"
|
||||
data-testid="app-header-file-name"
|
||||
>
|
||||
{isDesktop() && file?.name
|
||||
@ -252,14 +262,6 @@ function ProjectMenuPopover({
|
||||
)
|
||||
: APP_NAME}
|
||||
</span>
|
||||
{isDesktop() && project?.name && (
|
||||
<span
|
||||
className="hidden text-xs text-chalkboard-70 dark:text-chalkboard-40 whitespace-nowrap lg:block"
|
||||
data-testid="app-header-project-name"
|
||||
>
|
||||
{project.name}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<CustomIcon
|
||||
name="caretDown"
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
} from '@src/components/AvailableVarsHelpers'
|
||||
import type { Expr } from '@src/lang/wasm'
|
||||
import { useCalculateKclExpression } from '@src/lib/useCalculateKclExpression'
|
||||
import type { Selections } from '@src/lib/selections'
|
||||
|
||||
type ModalResolve = {
|
||||
value: string
|
||||
@ -25,6 +26,7 @@ type SetAngleLengthModalProps = InstanceProps<ModalResolve, ModalReject> & {
|
||||
value: number
|
||||
valueName: string
|
||||
shouldCreateVariable?: boolean
|
||||
selectionRanges: Selections
|
||||
}
|
||||
|
||||
export const createSetAngleLengthModal = create<
|
||||
@ -40,6 +42,7 @@ export const SetAngleLengthModal = ({
|
||||
value: initialValue,
|
||||
valueName,
|
||||
shouldCreateVariable: initialShouldCreateVariable = false,
|
||||
selectionRanges,
|
||||
}: SetAngleLengthModalProps) => {
|
||||
const [sign, setSign] = useState(Math.sign(Number(initialValue)))
|
||||
const [value, setValue] = useState(String(initialValue * sign))
|
||||
@ -59,6 +62,7 @@ export const SetAngleLengthModal = ({
|
||||
} = useCalculateKclExpression({
|
||||
value,
|
||||
initialVariableName: valueName,
|
||||
selectionRanges,
|
||||
})
|
||||
|
||||
return (
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
} from '@src/components/AvailableVarsHelpers'
|
||||
import type { Expr } from '@src/lang/wasm'
|
||||
import { useCalculateKclExpression } from '@src/lib/useCalculateKclExpression'
|
||||
import type { Selections } from '@src/lib/selections'
|
||||
|
||||
type ModalResolve = {
|
||||
value: string
|
||||
@ -27,6 +28,7 @@ type GetInfoModalProps = InstanceProps<ModalResolve, ModalReject> & {
|
||||
isSegNameEditable: boolean
|
||||
value?: number
|
||||
initialVariableName: string
|
||||
selectionRanges: Selections
|
||||
}
|
||||
|
||||
export const createInfoModal = create<
|
||||
@ -43,6 +45,7 @@ export const GetInfoModal = ({
|
||||
isSegNameEditable,
|
||||
value: initialValue,
|
||||
initialVariableName,
|
||||
selectionRanges,
|
||||
}: GetInfoModalProps) => {
|
||||
const [sign, setSign] = useState(Math.sign(Number(initialValue)))
|
||||
const [segName, setSegName] = useState(initialSegName)
|
||||
@ -60,7 +63,11 @@ export const GetInfoModal = ({
|
||||
newVariableName,
|
||||
isNewVariableNameUnique,
|
||||
newVariableInsertIndex,
|
||||
} = useCalculateKclExpression({ value: value, initialVariableName })
|
||||
} = useCalculateKclExpression({
|
||||
value: value,
|
||||
initialVariableName,
|
||||
selectionRanges,
|
||||
})
|
||||
|
||||
return (
|
||||
<Transition appear show={isOpen} as={Fragment}>
|
||||
|
@ -6,11 +6,13 @@ import { type InstanceProps, create } from 'react-modal-promise'
|
||||
import { ActionButton } from '@src/components/ActionButton'
|
||||
import { CreateNewVariable } from '@src/components/AvailableVarsHelpers'
|
||||
import { useCalculateKclExpression } from '@src/lib/useCalculateKclExpression'
|
||||
import type { Selections } from '@src/lib/selections'
|
||||
|
||||
type ModalResolve = { variableName: string }
|
||||
type ModalReject = boolean
|
||||
type SetVarNameModalProps = InstanceProps<ModalResolve, ModalReject> & {
|
||||
valueName: string
|
||||
selectionRanges: Selections
|
||||
}
|
||||
|
||||
export const createSetVarNameModal = create<
|
||||
@ -24,9 +26,14 @@ export const SetVarNameModal = ({
|
||||
onResolve,
|
||||
onReject,
|
||||
valueName,
|
||||
selectionRanges,
|
||||
}: SetVarNameModalProps) => {
|
||||
const { isNewVariableNameUnique, newVariableName, setNewVariableName } =
|
||||
useCalculateKclExpression({ value: '', initialVariableName: valueName })
|
||||
useCalculateKclExpression({
|
||||
value: '',
|
||||
initialVariableName: valueName,
|
||||
selectionRanges,
|
||||
})
|
||||
|
||||
return (
|
||||
<Transition appear show={isOpen} as={Fragment}>
|
||||
|
@ -83,7 +83,7 @@ export const ShareButton = memo(function ShareButton() {
|
||||
billingContext.tier === undefined
|
||||
|
||||
return (
|
||||
<Popover className="relative flex">
|
||||
<Popover className="relative hidden sm:flex">
|
||||
<Popover.Button
|
||||
as="div"
|
||||
className="relative group border-0 w-fit min-w-max p-0 rounded-l-full focus-visible:outline-appForeground"
|
||||
|
@ -1,5 +1,4 @@
|
||||
import type { Node } from '@rust/kcl-lib/bindings/Node'
|
||||
|
||||
import { removeDoubleNegatives } from '@src/components/AvailableVarsHelpers'
|
||||
import {
|
||||
GetInfoModal,
|
||||
@ -167,6 +166,7 @@ export async function applyConstraintIntersect({
|
||||
isSegNameEditable: !tagInfo?.isTagExisting,
|
||||
value: valueUsedInTransform,
|
||||
initialVariableName: 'offset',
|
||||
selectionRanges,
|
||||
})
|
||||
if (
|
||||
!variableName &&
|
||||
|
@ -113,6 +113,7 @@ export async function applyConstraintAbsDistance({
|
||||
await getModalInfo({
|
||||
value: forceVal,
|
||||
valueName: constraint === 'yAbs' ? 'yDis' : 'xDis',
|
||||
selectionRanges,
|
||||
})
|
||||
if (!isExprBinaryPart(valueNode))
|
||||
return Promise.reject('Invalid valueNode, is not a BinaryPart')
|
||||
|
@ -117,7 +117,8 @@ export async function applyConstraintAngleBetween({
|
||||
isSegNameEditable: !tagInfo?.isTagExisting,
|
||||
value: valueUsedInTransform,
|
||||
initialVariableName: 'angle',
|
||||
} as any)
|
||||
selectionRanges,
|
||||
})
|
||||
if (
|
||||
segName === tagInfo?.tag &&
|
||||
Number(value) === valueUsedInTransform &&
|
||||
|
@ -123,7 +123,8 @@ export async function applyConstraintHorzVertDistance({
|
||||
isSegNameEditable: !tagInfo?.isTagExisting,
|
||||
value: valueUsedInTransform,
|
||||
initialVariableName: constraint === 'setHorzDistance' ? 'xDis' : 'yDis',
|
||||
} as any)
|
||||
selectionRanges,
|
||||
})
|
||||
if (
|
||||
!variableName &&
|
||||
segName === tagInfo?.tag &&
|
||||
|
@ -143,6 +143,7 @@ export async function applyConstraintAngleLength({
|
||||
value: forceVal,
|
||||
valueName: angleOrLength === 'setAngle' ? 'angle' : 'length',
|
||||
shouldCreateVariable: true,
|
||||
selectionRanges,
|
||||
})
|
||||
if (!isExprBinaryPart(valueNode))
|
||||
return Promise.reject('Invalid valueNode, is not a BinaryPart')
|
||||
|
@ -178,9 +178,9 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Popover className="relative">
|
||||
<Popover className="relative grid">
|
||||
<Popover.Button
|
||||
className="relative group border-0 w-fit min-w-max p-0 rounded-l-full focus-visible:outline-appForeground"
|
||||
className="m-0 relative group border-0 w-fit min-w-max p-0 rounded-l-full rounded-r focus-visible:outline-appForeground"
|
||||
data-testid="user-sidebar-toggle"
|
||||
>
|
||||
<div className="flex items-center">
|
||||
|
@ -52,6 +52,7 @@ export function useConvertToVariable(range?: SourceRange) {
|
||||
try {
|
||||
const { variableName } = await getVarNameModal({
|
||||
valueName: valueName || 'var',
|
||||
selectionRanges: context.selectionRanges,
|
||||
})
|
||||
|
||||
const { modifiedAst: _modifiedAst, pathToReplacedNode } =
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
|
||||
import { useModelingContext } from '@src/hooks/useModelingContext'
|
||||
import { useKclContext } from '@src/lang/KclProvider'
|
||||
import { findUniqueName } from '@src/lang/create'
|
||||
import type { PrevVariable } from '@src/lang/queryAst'
|
||||
@ -12,6 +10,7 @@ import { getCalculatedKclExpressionValue } from '@src/lib/kclHelpers'
|
||||
import { kclManager } from '@src/lib/singletons'
|
||||
import { err } from '@src/lib/trap'
|
||||
import { getInVariableCase } from '@src/lib/utils'
|
||||
import type { Selections } from '@src/lib/selections'
|
||||
|
||||
const isValidVariableName = (name: string) =>
|
||||
/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)
|
||||
@ -25,10 +24,12 @@ export function useCalculateKclExpression({
|
||||
value,
|
||||
initialVariableName: valueName = '',
|
||||
sourceRange,
|
||||
selectionRanges,
|
||||
}: {
|
||||
value: string
|
||||
initialVariableName?: string
|
||||
sourceRange?: SourceRange
|
||||
selectionRanges: Selections
|
||||
}): {
|
||||
inputRef: React.RefObject<HTMLInputElement>
|
||||
valueNode: Expr | null
|
||||
@ -45,12 +46,10 @@ export function useCalculateKclExpression({
|
||||
// has completed
|
||||
const [isExecuting, setIsExecuting] = useState(false)
|
||||
const { variables, code } = useKclContext()
|
||||
const { context } = useModelingContext()
|
||||
// If there is no selection, use the end of the code
|
||||
// so all variables are available
|
||||
const selectionRange:
|
||||
| (typeof context)['selectionRanges']['graphSelections'][number]['codeRef']['range']
|
||||
| undefined = context.selectionRanges.graphSelections[0]?.codeRef?.range
|
||||
const selectionRange: SourceRange | undefined =
|
||||
selectionRanges.graphSelections[0]?.codeRef?.range
|
||||
// If there is no selection, use the end of the code
|
||||
// If we don't memoize this, we risk an infinite set/read state loop
|
||||
const endingSourceRange = useMemo(
|
||||
|
@ -29,7 +29,6 @@ import {
|
||||
applyConstraintHorzVert,
|
||||
horzVertInfo,
|
||||
} from '@src/components/Toolbar/HorzVert'
|
||||
import { intersectInfo } from '@src/components/Toolbar/Intersect'
|
||||
import {
|
||||
applyRemoveConstrainingValues,
|
||||
removeConstrainingValuesInfo,
|
||||
@ -155,6 +154,7 @@ import type { Plane } from '@rust/kcl-lib/bindings/Plane'
|
||||
import type { Point3d } from '@rust/kcl-lib/bindings/ModelingCmd'
|
||||
import { getNodePathFromSourceRange } from '@src/lang/queryAstNodePathUtils'
|
||||
import { letEngineAnimateAndSyncCamAfter } from '@src/clientSideScene/CameraControls'
|
||||
import { intersectInfo } from '@src/components/Toolbar/Intersect'
|
||||
|
||||
export type SetSelections =
|
||||
| {
|
||||
|
@ -221,10 +221,7 @@ const Home = () => {
|
||||
|
||||
return (
|
||||
<div className="relative flex flex-col items-stretch h-screen w-screen overflow-hidden">
|
||||
<AppHeader
|
||||
nativeFileMenuCreated={nativeFileMenuCreated}
|
||||
showToolbar={false}
|
||||
/>
|
||||
<AppHeader nativeFileMenuCreated={nativeFileMenuCreated} />
|
||||
<div className="overflow-hidden self-stretch w-full flex-1 home-layout max-w-4xl lg:max-w-5xl xl:max-w-7xl px-4 mx-auto mt-8 lg:mt-24 lg:px-0">
|
||||
<HomeHeader
|
||||
setQuery={setQuery}
|
||||
|