Compare commits
1 Commits
v0.50.0
...
extrude-ma
Author | SHA1 | Date | |
---|---|---|---|
2d350a93ed |
@ -72,8 +72,15 @@ function CommandBarHeader({ children }: React.PropsWithChildren<{}>) {
|
|||||||
)}
|
)}
|
||||||
{selectedCommand?.name}
|
{selectedCommand?.name}
|
||||||
</p>
|
</p>
|
||||||
{Object.entries(selectedCommand?.args || {}).map(
|
{Object.entries(selectedCommand?.args || {})
|
||||||
([argName, arg], i) => (
|
.filter(([argName, _]) =>
|
||||||
|
selectedCommand?.args
|
||||||
|
? selectedCommand?.args[argName]?.required ||
|
||||||
|
(argName in argumentsToSubmit && argumentsToSubmit[argName])
|
||||||
|
: false
|
||||||
|
)
|
||||||
|
.map(([argName, arg], i) => (
|
||||||
|
<div className="relative group" key={argName}>
|
||||||
<button
|
<button
|
||||||
disabled={!isReviewing && currentArgument?.name === argName}
|
disabled={!isReviewing && currentArgument?.name === argName}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -84,7 +91,6 @@ function CommandBarHeader({ children }: React.PropsWithChildren<{}>) {
|
|||||||
data: { arg: { ...arg, name: argName } },
|
data: { arg: { ...arg, name: argName } },
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
key={argName}
|
|
||||||
className={`relative w-fit px-2 py-1 rounded-sm flex gap-2 items-center border ${
|
className={`relative w-fit px-2 py-1 rounded-sm flex gap-2 items-center border ${
|
||||||
argName === currentArgument?.name
|
argName === currentArgument?.name
|
||||||
? 'disabled:bg-energy-10/50 dark:disabled:bg-energy-10/20 disabled:border-energy-10 dark:disabled:border-energy-10 disabled:text-chalkboard-100 dark:disabled:text-chalkboard-10'
|
? 'disabled:bg-energy-10/50 dark:disabled:bg-energy-10/20 disabled:border-energy-10 dark:disabled:border-energy-10 disabled:text-chalkboard-100 dark:disabled:text-chalkboard-10'
|
||||||
@ -119,9 +125,26 @@ function CommandBarHeader({ children }: React.PropsWithChildren<{}>) {
|
|||||||
</small>
|
</small>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
)
|
{!arg.required && (
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
commandBarSend({
|
||||||
|
type: 'Remove argument',
|
||||||
|
data: { [argName]: { ...arg, name: argName } },
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
className="invisible group-hover:visible absolute top-0 right-0 -translate-y-1/2 !p-0 flex items-center justify-center rounded-sm border-none bg-none"
|
||||||
|
>
|
||||||
|
<CustomIcon
|
||||||
|
name="close"
|
||||||
|
className="w-4 h-4 bg-destroy-80 dark:bg-destroy-30 hover:bg-destroy-70 dark:hover:bg-destroy-0 text-destroy-10 dark:text-destroy-80"
|
||||||
|
/>
|
||||||
|
<span className="sr-only">Remove argument</span>
|
||||||
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
{isReviewing ? <ReviewingButton /> : <GatheringArgsButton />}
|
{isReviewing ? <ReviewingButton /> : <GatheringArgsButton />}
|
||||||
</div>
|
</div>
|
||||||
<div className="block w-full my-2 h-[1px] bg-chalkboard-20 dark:bg-chalkboard-80" />
|
<div className="block w-full my-2 h-[1px] bg-chalkboard-20 dark:bg-chalkboard-80" />
|
||||||
|
@ -1,12 +1,21 @@
|
|||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
import CommandBarHeader from './CommandBarHeader'
|
import CommandBarHeader from './CommandBarHeader'
|
||||||
import { useHotkeys } from 'react-hotkeys-hook'
|
import { useHotkeys } from 'react-hotkeys-hook'
|
||||||
|
import { ActionButton } from 'components/ActionButton'
|
||||||
|
|
||||||
function CommandBarReview({ stepBack }: { stepBack: () => void }) {
|
function CommandBarReview({ stepBack }: { stepBack: () => void }) {
|
||||||
const { commandBarState, commandBarSend } = useCommandsContext()
|
const { commandBarState, commandBarSend } = useCommandsContext()
|
||||||
const {
|
const {
|
||||||
context: { argumentsToSubmit, selectedCommand },
|
context: { argumentsToSubmit, selectedCommand },
|
||||||
} = commandBarState
|
} = commandBarState
|
||||||
|
const optionalArgsNotAdded = Object.entries(
|
||||||
|
selectedCommand?.args || {}
|
||||||
|
).filter(
|
||||||
|
([key, val]) =>
|
||||||
|
selectedCommand?.args &&
|
||||||
|
!selectedCommand.args[key].required &&
|
||||||
|
!argumentsToSubmit[key]
|
||||||
|
)
|
||||||
|
|
||||||
useHotkeys('backspace', stepBack, {
|
useHotkeys('backspace', stepBack, {
|
||||||
enableOnFormTags: true,
|
enableOnFormTags: true,
|
||||||
@ -46,7 +55,7 @@ function CommandBarReview({ stepBack }: { stepBack: () => void }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CommandBarHeader>
|
<CommandBarHeader>
|
||||||
<p className="px-4">Confirm {selectedCommand?.name}</p>
|
<p className="px-4 py-1">Confirm {selectedCommand?.name}</p>
|
||||||
<form
|
<form
|
||||||
id="review-form"
|
id="review-form"
|
||||||
className="absolute opacity-0 inset-0 pointer-events-none"
|
className="absolute opacity-0 inset-0 pointer-events-none"
|
||||||
@ -74,6 +83,41 @@ function CommandBarReview({ stepBack }: { stepBack: () => void }) {
|
|||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</form>
|
</form>
|
||||||
|
{optionalArgsNotAdded.length > 0 && (
|
||||||
|
<>
|
||||||
|
<div className="block w-full my-2 h-[1px] bg-chalkboard-20 dark:bg-chalkboard-80" />
|
||||||
|
<div className="flex flex-wrap px-4 gap-2 items-center">
|
||||||
|
{optionalArgsNotAdded.map(([key, _]) => {
|
||||||
|
const arg = selectedCommand?.args
|
||||||
|
? selectedCommand?.args[key]
|
||||||
|
: undefined
|
||||||
|
if (!arg) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ActionButton
|
||||||
|
Element="button"
|
||||||
|
key={key}
|
||||||
|
className="text-xs [&:not(:hover)]:border-transparent gap-0.5"
|
||||||
|
onClick={() => {
|
||||||
|
commandBarSend({
|
||||||
|
type: 'Edit argument',
|
||||||
|
data: { arg: { ...arg, name: key } },
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
icon={{
|
||||||
|
icon: 'plus',
|
||||||
|
bgClassName: '!bg-transparent',
|
||||||
|
iconClassName:
|
||||||
|
'text-chalkboard-10 dark:text-chalkboard-100',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{key}
|
||||||
|
</ActionButton>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</CommandBarHeader>
|
</CommandBarHeader>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ export type CustomIconName =
|
|||||||
| 'line'
|
| 'line'
|
||||||
| 'move'
|
| 'move'
|
||||||
| 'parallel'
|
| 'parallel'
|
||||||
|
| 'plus'
|
||||||
| 'search'
|
| 'search'
|
||||||
| 'sketch'
|
| 'sketch'
|
||||||
| 'vertical'
|
| 'vertical'
|
||||||
@ -297,6 +298,22 @@ export const CustomIcon = ({
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
case 'plus':
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...props}
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M9.5 9.5V5.5H10.5V9.5H14.5V10.5H10.5V14.5H9.5V10.5H5.5V9.5H9.5Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
case 'search':
|
case 'search':
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
|
@ -15,6 +15,7 @@ export type ModelingCommandSchema = {
|
|||||||
selection: Selections // & { type: 'face' } would be cool to lock that down
|
selection: Selections // & { type: 'face' } would be cool to lock that down
|
||||||
// result: (typeof EXTRUSION_RESULTS)[number]
|
// result: (typeof EXTRUSION_RESULTS)[number]
|
||||||
distance: number
|
distance: number
|
||||||
|
makeVariable?: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,6 +53,10 @@ export const modelingMachineConfig: CommandSetConfig<
|
|||||||
defaultValue: 5,
|
defaultValue: 5,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
makeVariable: {
|
||||||
|
inputType: 'string',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import { Selections } from 'lib/selections'
|
|||||||
|
|
||||||
export const commandBarMachine = createMachine(
|
export const commandBarMachine = createMachine(
|
||||||
{
|
{
|
||||||
/** @xstate-layout N4IgpgJg5mDOIC5QGED2BbdBDAdhABAEJYBOAxMgDaqxgDaADALqKgAONAlgC6eo6sQAD0QBaAJwA6AGwAmAKwBmBoukAWafIAcDcSoA0IAJ6JZDaZIDs8hgzV6AjA61a1DWQF8PhtJlwFiciowUkYWJBAOWB4+AQiRBFF5CwdpcVkHS1lpVyU5QxNEh1lFGTUsrUUtOQd5SwZLLx8MbDwiUkkqGkgyAHk2MBwwwSiY-kEEswdJNWcNbPFLNMr5AsRFWUtJcVSdRR2VVMUmkF9WgI6u2ggyADFONv98WkowAGNufDeW-2GI0d443iiHESkktUUG1klTsSi0awQDgYWhmqkWjnUslBWhOZyegU61GuZAAghACN8-HhYH92FxAXFQAlRA5FpJ5FjFPYtNDpIpLOkEW4GNs4eJxJoGvJxOVcT82gSrj0AEpgdCoABuYC+8ogNOYI3psQmYlkGUkU2slhc6mkmUUCIyKLc4i0lkU8iUyjUHLlVIuJEkAGUwK8Pg8oDr-WQQ2HPpTzrTIkagUzEDkLHZkQK1CUtKCHAiNlsdjkVAdFEc-ed2oGAOJYbgACzAJAj+FIUAAruhBtxYGQACJwUPveO6pMA43AhA5UqWXOzBjS-nOR3LySqXNODTyZwONTV-GXXXPUcfHqTlOM4TrSublb5-lLewlIVySRaOrmGw-jLSI8FRPf0zzjS8HHCOlogZE1ERUEUSgPa05yQ1ZjEQeZP2-VwDzUN1zEabxTlPAkG2bVt207Hs+wHZAm1wGAvi7EgSD7DsSG7XscG4K9oOnNNEVUeQZGSOxc0qaQ7HhdDBJFeRc35extGkNI+UAgNJDIls2xwSMqK4-tJBJAB3LAYl0-AHjYLtuBjLsACN0B4djOL7XixhvBIDxUT8qj5VIkTwtQHRk8oUQcD15LMXQclcdTa00xttMojjqO42BJAANSwShOAgRsIzICB+DASQHg1VAAGtSo1HK8sbMASVSgz3JgmdMnKGYzRlbIdGXA8EX8zd3RsTY9yyY4iLxID6ySiiLP0misrq-LeF0shWxIVBAzYShGwAM229BJFq3LVsa5q3INf5r1gg9JIfXqqh0TQsiFTYrCyJZRpsXJ4oJVUNU4MBjLsxznITX5rqgjzYMsaZtGXaVNhcZFKgRd0RXUdJ6mUXQXX+jpAeB0GyQIRbuNa-jbwQcVSmhAUeTkWQ3HyGSBVKDQMyRAKAsJwNiZBshVXVLUXLSnjoeTPjUxpnmpFtcVs1cPNBq5T8fR5DrKwaHEppIomwCBoWAFEIGcinJcg6XYZnTRhJsbQJU9VlQTVtQNbqcVZhsSFxH5zoWzeSr2ya1z0qKkqypwCrqpOlaGrDiX9WtqdZYSeSEeXEplCceo1xkvQLGCmUIp0Mwck8fWQMVIOQ4spODIHYqcFK8qqpqhPuAu8P+zoCDDRlzzTCkCVWWlSxrBceTygRFxZHZNJbE2VQ5AFAO6PeevI0bmiNpY7bJF2g6jvjs7E8u9KqfTxAkK2fZYuRvdYUGjQZnqYVxRKdx-ZOHBUAgHAQQ00AyD1tgJUQCwLQMEyHUG0Gh7SOmmDuGB6gOTyVBMkDeRJIBgLahA4oFo8zWlSPUT00o0KFA9NMYKrhKwbH2GaQ81cawEljGOdskM8B4OpgkWY9MV5ZjqLUN6MlqGojoRFEo6QWYb1PC8McuCbpD1gosLYrhkTZCxNIawhYxEfW0HhCKKgzT8lBAHLS809KX37Dwm+iIWZSEinjTRy51BFnvNofM7hGZfgXBYuaOlrG9wyiZMya1IxWRsnY4eDi2TONsK45IaghQbEkO4VIKlsaVE2AE8iQTxZN2WufCJMS7o6JSBKNQLp7CT35EKZw2wnDVDyCvBczDmg10NsbYyZS7aZHBNU58q8sTQgxnud+kVsjyQzHrTprDLh11DjY+AyjwFy00DQ2EaQBSLAPLIDGWRNw2BUiXHkwVCJeCAA */
|
/** @xstate-layout N4IgpgJg5mDOIC5QGED2BbdBDAdhABAEJYBOAxMgDaqxgDaADALqKgAONAlgC6eo6sQAD0QBaAJwA6AGwAmAKwBmBoukAWafIAcDcSoA0IAJ6JZDaZIDs8hgzV6AjA61a1DWQF8PhtJlwFiciowUkYWJBAOWB4+AQiRBFF5CwdpcVkHS1lpVyU5QxNEh1lFGTUsrUUtOQd5SwZLLx8MbDwiUkkqGkgyAHk2MBwwwSiY-kEEswdJNWcNbPFLNMr5AsRFWUtJcVSdRR2VVMUmkF9WgI6u2ggyADFONv98WkowAGNufDeW-2GI0d443iiHESkktUUG1klTsSi0awQDgYWhmqkWjnUslBWhOZyegU61GuZAAghACN8-HhYH92FxAXFQAlRA5FpJ5FjFPYtNDpIpLOkEW4GNs4eJxJoGvJxOVcT82gSrj0AEpgdCoABuYC+8ogNOYI3psQmYlkGUkU2slhc6mkmUUCIyKLc4i0lkU8iUyjUHLlVIuJEkAGUwK8Pg8oDr-WQQ2HPpTzrTIkagUzEDkLHZkQK1CUtKCHAiNlsdjkVAdFEc-ed2oG8W0Xu9uD0kwDjcCEJDplUPfn+Ut7CUhXJJFo6uYbBOMtJq-jLrrnqGmy2HOE6dEGSbESoRSUHOVqpV99Zh7JR+PXPu1G7zI1vKcFwSAOJYbgACzAJAj+FIUAAruggzcLAFBvrgMBfH+JAkEBP4kP+gE4NwrYpoywiIA4qjyDIyR2LmlTSHY8LGBhyjsrm-L2No0hpHys4Kh0L7vp+36-gBQEgQAInAS4fFGiYGv8qFbjkpSWLmswMNK-LOI6UmSKouZOBo8jOPu9EBpITEfl+OCRmxiHAZIJIAO5YDEen4A8bB-twMZ-gARugPBwQhQEoRu7ZpoibilJU1SVnaRFqA6JEIAe4IevIua2BKLhqBptZaa+OmsfB7FIbAkgAGpYJQnAQK+EZkBA-BgJIDwaqgADW5UanlBWvmAJLpYZHljGhCSZOUMxmjK2Q6FJ+4Iny3bujYmyqVkxz3vWmnaSxlkGRxOUNYVvB6WQn4kKggZsJQr4AGa7egkj1fl63Na17mCeuHVbvuhEKTyokuBOWRCpsVhZEsE02LkiUEqqGqcGAJn2U5LkJr8t3Jp5qboQgljTNoUnSpsb0uKFhTuiK6jpPUyi6C6gMdMDoPg2SBDLUh7Wbh24qlNCAovWabj5GFAqlBoGZIqkTh2qTgbk2DZCquqWquRlyGw22CNdQwrJlGkehuq4eYjVyo4+jy3WVg0OKzY+ZNgCDosAKIQC5NMy2ucP3R2mjYTY2gSp6rKgpraja3U4qzDYkLiELnQfm81Xfi1bmZSVZUVTgVW1Wda1NZH0v6nbcudYg0Uo1JJTKE49SyWFegWCFMqYToZg5J4Rv+klyCh+Hlmp4ZIGlTg5WVTVdXJ82rccXQq6GvDWcIFi2x2qCizWC40XlAiLhnskejuO6NGbEHdc1oqTcR9d0fbbtkj7UdJ1JxdKcH8BdNeYjx5bPsORjukqmwiNGgzPUwriiU7hb80euz4UqLX0tfEC4tNTahtrfeWpg7DTAlMeQ8XIOSrDCrsdk4gqjImRD6TCIVg4LV0mAqOwExZqigVLNqw8hKjwepoUo7g4SzE0EFQsGDpTbFcG6AhgUlheHvDgVAEA4CCDmrWEeDtvKiAWBaRWVobQaHtI6aYylzDFGUIpSsCVt5zjrESSAUj6YyOKBaPM1pUj1E9NKdBhQPTTBCq4SsGx9hs2DrGJs35oZ4GMXfBIswmabG9FJZGdRZBFlUqiZxmESjpFkLowBO95z10bB8IxdDpGIxntrZE2QsTSGsBw+xX1tDXkwioM0-JQREJASQ6hHE-FwMRAkqQUUiZ5KkuoIslZ2QuBlFaGiWQEm1OYvUm2WVTLmQ2pGaytkmlj2KGydpthOnJDUEKDYkh3CpBovjSomxRmpSWuA1al8ZkLIYUscEEo1AunsJYd0lghTOG2E4aoeRgniUSQ+IBJszYmUuY7TI4I7n9lUHIdIxEcZRPKFFbI0UMyGySfokO7xm6RgHplIF3laivMZgRNm7NsaIACgpV2SxajYMhDNLwQA */
|
||||||
context: {
|
context: {
|
||||||
commands: [] as Command[],
|
commands: [] as Command[],
|
||||||
selectedCommand: undefined as Command | undefined,
|
selectedCommand: undefined as Command | undefined,
|
||||||
@ -167,6 +167,19 @@ export const commandBarMachine = createMachine(
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'Remove argument': [
|
||||||
|
{
|
||||||
|
target: 'Review',
|
||||||
|
cond: 'Is current argument',
|
||||||
|
actions: 'Remove argument',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: 'Gathering arguments',
|
||||||
|
internal: true,
|
||||||
|
actions: 'Remove argument',
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -185,17 +198,7 @@ export const commandBarMachine = createMachine(
|
|||||||
|
|
||||||
'Remove argument': {
|
'Remove argument': {
|
||||||
target: 'Review',
|
target: 'Review',
|
||||||
actions: [
|
actions: ['Remove argument'],
|
||||||
assign({
|
|
||||||
argumentsToSubmit: (context, event) => {
|
|
||||||
const argName = Object.keys(event.data)[0]
|
|
||||||
const { argumentsToSubmit } = context
|
|
||||||
const newArgumentsToSubmit = { ...argumentsToSubmit }
|
|
||||||
newArgumentsToSubmit[argName] = undefined
|
|
||||||
return newArgumentsToSubmit
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
|
|
||||||
'Edit argument': {
|
'Edit argument': {
|
||||||
@ -362,10 +365,25 @@ export const commandBarMachine = createMachine(
|
|||||||
return args
|
return args
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
'Remove argument': assign({
|
||||||
|
argumentsToSubmit: (context, event) => {
|
||||||
|
if (event.type !== 'Remove argument') return context.argumentsToSubmit
|
||||||
|
const argName = Object.keys(event.data)[0]
|
||||||
|
const { argumentsToSubmit } = context
|
||||||
|
const newArgumentsToSubmit = { ...argumentsToSubmit }
|
||||||
|
delete newArgumentsToSubmit[argName]
|
||||||
|
return newArgumentsToSubmit
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
guards: {
|
guards: {
|
||||||
'Command needs review': (context, _) =>
|
'Command needs review': (context, _) =>
|
||||||
context.selectedCommand?.needsReview || false,
|
context.selectedCommand?.needsReview || false,
|
||||||
|
'Is current argument': (context, event) => {
|
||||||
|
if (event.type !== 'Remove argument') return false
|
||||||
|
const argName = Object.keys(event.data)[0]
|
||||||
|
return argName === context.currentArgument?.name
|
||||||
|
},
|
||||||
},
|
},
|
||||||
services: {
|
services: {
|
||||||
'Validate argument': (context, event) => {
|
'Validate argument': (context, event) => {
|
||||||
@ -381,6 +399,10 @@ export const commandBarMachine = createMachine(
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
for (const [argName, arg] of Object.entries(
|
for (const [argName, arg] of Object.entries(
|
||||||
context.argumentsToSubmit
|
context.argumentsToSubmit
|
||||||
|
).filter(([argName, _]) =>
|
||||||
|
context.selectedCommand?.args
|
||||||
|
? context.selectedCommand?.args[argName]?.required
|
||||||
|
: false
|
||||||
)) {
|
)) {
|
||||||
let argConfig = context.selectedCommand!.args![argName]
|
let argConfig = context.selectedCommand!.args![argName]
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user