Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
da323e22d4 | |||
8dc3628e9b | |||
253744867b | |||
c45eb1e3e3 | |||
758aac9328 | |||
309943cf2c | |||
b3d4ab91fc | |||
5e73fa45f0 | |||
17d23a17db |
@ -12,6 +12,7 @@ import {
|
|||||||
TEST_SETTINGS_ONBOARDING_START,
|
TEST_SETTINGS_ONBOARDING_START,
|
||||||
} from './storageStates'
|
} from './storageStates'
|
||||||
import * as TOML from '@iarna/toml'
|
import * as TOML from '@iarna/toml'
|
||||||
|
import { Coords2d } from 'lang/std/sketch'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
debug helper: unfortunately we do rely on exact coord mouse clicks in a few places
|
debug helper: unfortunately we do rely on exact coord mouse clicks in a few places
|
||||||
@ -954,9 +955,8 @@ test.describe('Command bar tests', () => {
|
|||||||
let cmdSearchBar = page.getByPlaceholder('Search commands')
|
let cmdSearchBar = page.getByPlaceholder('Search commands')
|
||||||
|
|
||||||
// First try opening the command bar and closing it
|
// First try opening the command bar and closing it
|
||||||
// It has a different label on mac and windows/linux, "Meta+K" and "Ctrl+/" respectively
|
|
||||||
await page
|
await page
|
||||||
.getByRole('button', { name: 'Ctrl+/' })
|
.getByRole('button', { name: 'Commands', exact: false })
|
||||||
.or(page.getByRole('button', { name: '⌘K' }))
|
.or(page.getByRole('button', { name: '⌘K' }))
|
||||||
.click()
|
.click()
|
||||||
await expect(cmdSearchBar).toBeVisible()
|
await expect(cmdSearchBar).toBeVisible()
|
||||||
@ -1265,6 +1265,72 @@ test('ProgramMemory can be serialised', async ({ page }) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('Hovering over 3d features highlights code', async ({ page }) => {
|
||||||
|
const u = getUtils(page)
|
||||||
|
await page.addInitScript(async () => {
|
||||||
|
localStorage.setItem(
|
||||||
|
'persistCode',
|
||||||
|
`const part001 = startSketchOn('-XZ')
|
||||||
|
|> startProfileAt([20, 0], %)
|
||||||
|
|> line([7.13, 4 + 0], %)
|
||||||
|
|> angledLine({ angle: 3 + 0, length: 3.14 + 0 }, %)
|
||||||
|
|> lineTo([20.14 + 0, -0.14 + 0], %)
|
||||||
|
|> xLineTo(29 + 0, %)
|
||||||
|
|> yLine(-3.14 + 0, %, 'a')
|
||||||
|
|> xLine(1.63, %)
|
||||||
|
|> angledLineOfXLength({ angle: 3 + 0, length: 3.14 }, %)
|
||||||
|
|> angledLineOfYLength({ angle: 30, length: 3 + 0 }, %)
|
||||||
|
|> angledLineToX({ angle: 22.14 + 0, to: 12 }, %)
|
||||||
|
|> angledLineToY({ angle: 30, to: 11.14 }, %)
|
||||||
|
|> angledLineThatIntersects({
|
||||||
|
angle: 3.14,
|
||||||
|
intersectTag: 'a',
|
||||||
|
offset: 0
|
||||||
|
}, %)
|
||||||
|
|> tangentialArcTo([13.14 + 0, 13.14], %)
|
||||||
|
|> close(%)
|
||||||
|
|> extrude(5 + 7, %)
|
||||||
|
`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
await page.setViewportSize({ width: 1000, height: 500 })
|
||||||
|
await page.goto('/')
|
||||||
|
await u.waitForAuthSkipAppStart()
|
||||||
|
|
||||||
|
const extrusionTop: Coords2d = [800, 240]
|
||||||
|
const flatExtrusionFace: Coords2d = [960, 160]
|
||||||
|
const arc: Coords2d = [840, 160]
|
||||||
|
const close: Coords2d = [720, 200]
|
||||||
|
const nothing: Coords2d = [600, 200]
|
||||||
|
|
||||||
|
await page.mouse.move(nothing[0], nothing[1])
|
||||||
|
await page.mouse.click(nothing[0], nothing[1])
|
||||||
|
|
||||||
|
await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
|
||||||
|
await page.waitForTimeout(200)
|
||||||
|
|
||||||
|
await page.mouse.move(extrusionTop[0], extrusionTop[1])
|
||||||
|
await expect(page.getByTestId('hover-highlight')).toBeVisible()
|
||||||
|
await page.mouse.move(nothing[0], nothing[1])
|
||||||
|
await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
|
||||||
|
|
||||||
|
await page.mouse.move(arc[0], arc[1])
|
||||||
|
await expect(page.getByTestId('hover-highlight')).toBeVisible()
|
||||||
|
await page.mouse.move(nothing[0], nothing[1])
|
||||||
|
await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
|
||||||
|
|
||||||
|
await page.mouse.move(close[0], close[1])
|
||||||
|
await expect(page.getByTestId('hover-highlight')).toBeVisible()
|
||||||
|
await page.mouse.move(nothing[0], nothing[1])
|
||||||
|
await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
|
||||||
|
|
||||||
|
await page.mouse.move(flatExtrusionFace[0], flatExtrusionFace[1])
|
||||||
|
await expect(page.getByTestId('hover-highlight')).toHaveCount(5) // multiple lines
|
||||||
|
await page.mouse.move(nothing[0], nothing[1])
|
||||||
|
await page.waitForTimeout(100)
|
||||||
|
await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
|
||||||
|
})
|
||||||
|
|
||||||
test("Various pipe expressions should and shouldn't allow edit and or extrude", async ({
|
test("Various pipe expressions should and shouldn't allow edit and or extrude", async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 48 KiB |
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "untitled-app",
|
"name": "untitled-app",
|
||||||
"version": "0.20.2",
|
"version": "0.21.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.16.0",
|
"@codemirror/autocomplete": "^6.16.0",
|
||||||
|
@ -74,5 +74,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"productName": "Zoo Modeling App",
|
"productName": "Zoo Modeling App",
|
||||||
"version": "0.20.2"
|
"version": "0.21.0"
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import { engineCommandManager, kclManager } from 'lib/singletons'
|
|||||||
import { useModelingContext } from 'hooks/useModelingContext'
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
import { ActionButton } from 'components/ActionButton'
|
import { ActionButton } from 'components/ActionButton'
|
||||||
import usePlatform from 'hooks/usePlatform'
|
|
||||||
import { isSingleCursorInPipe } from 'lang/queryAst'
|
import { isSingleCursorInPipe } from 'lang/queryAst'
|
||||||
import { useKclContext } from 'lang/KclProvider'
|
import { useKclContext } from 'lang/KclProvider'
|
||||||
import {
|
import {
|
||||||
@ -14,7 +13,6 @@ import {
|
|||||||
import { useStore } from 'useStore'
|
import { useStore } from 'useStore'
|
||||||
|
|
||||||
export const Toolbar = () => {
|
export const Toolbar = () => {
|
||||||
const platform = usePlatform()
|
|
||||||
const { commandBarSend } = useCommandsContext()
|
const { commandBarSend } = useCommandsContext()
|
||||||
const { state, send, context } = useModelingContext()
|
const { state, send, context } = useModelingContext()
|
||||||
const toolbarButtonsRef = useRef<HTMLUListElement>(null)
|
const toolbarButtonsRef = useRef<HTMLUListElement>(null)
|
||||||
@ -274,17 +272,8 @@ export const Toolbar = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-full flex items-stretch rounded-l-sm rounded-r-full bg-chalkboard-10/80 dark:bg-chalkboard-110/70 relative">
|
<menu className="max-w-full overflow-hidden whitespace-nowrap rounded px-1.5 py-0.5 backdrop-blur-sm bg-chalkboard-10/80 dark:bg-chalkboard-110/70 relative">
|
||||||
<menu className="flex-1 pl-1 pr-2 py-0 overflow-hidden rounded-l-sm whitespace-nowrap border-solid border border-primary/30 dark:border-chalkboard-90 border-r-0">
|
<ToolbarButtons />
|
||||||
<ToolbarButtons />
|
</menu>
|
||||||
</menu>
|
|
||||||
<ActionButton
|
|
||||||
Element="button"
|
|
||||||
onClick={() => commandBarSend({ type: 'Open' })}
|
|
||||||
className="rounded-r-full pr-4 self-stretch border-primary/30 hover:border-primary dark:border-chalkboard-80 dark:bg-chalkboard-80 text-primary"
|
|
||||||
>
|
|
||||||
{platform === 'macos' ? '⌘K' : 'Ctrl+/'}
|
|
||||||
</ActionButton>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,8 @@ export const ClientSideScene = ({
|
|||||||
cursor = 'grabbing'
|
cursor = 'grabbing'
|
||||||
} else if (
|
} else if (
|
||||||
state.matches('Sketch.Line tool') ||
|
state.matches('Sketch.Line tool') ||
|
||||||
state.matches('Sketch.Tangential arc to')
|
state.matches('Sketch.Tangential arc to') ||
|
||||||
|
state.matches('Sketch.Rectangle tool')
|
||||||
) {
|
) {
|
||||||
cursor = 'crosshair'
|
cursor = 'crosshair'
|
||||||
} else {
|
} else {
|
||||||
@ -104,9 +105,9 @@ export const ClientSideScene = ({
|
|||||||
style={{ cursor: cursor }}
|
style={{ cursor: cursor }}
|
||||||
className={`absolute inset-0 h-full w-full transition-all duration-300 ${
|
className={`absolute inset-0 h-full w-full transition-all duration-300 ${
|
||||||
hideClient ? 'opacity-0' : 'opacity-100'
|
hideClient ? 'opacity-0' : 'opacity-100'
|
||||||
} ${hideServer ? 'bg-black' : ''} ${
|
} ${hideServer ? 'bg-chalkboard-10 dark:bg-chalkboard-100' : ''} ${
|
||||||
!hideClient && !hideServer && state.matches('Sketch')
|
!hideClient && !hideServer && state.matches('Sketch')
|
||||||
? 'bg-black/80'
|
? 'bg-chalkboard-10/80 dark:bg-chalkboard-100/80'
|
||||||
: ''
|
: ''
|
||||||
}`}
|
}`}
|
||||||
></div>
|
></div>
|
||||||
|
@ -97,6 +97,7 @@ import {
|
|||||||
getRectangleCallExpressions,
|
getRectangleCallExpressions,
|
||||||
updateRectangleSketch,
|
updateRectangleSketch,
|
||||||
} from 'lib/rectangleTool'
|
} from 'lib/rectangleTool'
|
||||||
|
import { getThemeColorForThreeJs } from 'lib/theme'
|
||||||
|
|
||||||
type DraftSegment = 'line' | 'tangentialArcTo'
|
type DraftSegment = 'line' | 'tangentialArcTo'
|
||||||
|
|
||||||
@ -356,6 +357,7 @@ export class SceneEntities {
|
|||||||
id: sketchGroup.start.__geoMeta.id,
|
id: sketchGroup.start.__geoMeta.id,
|
||||||
pathToNode: segPathToNode,
|
pathToNode: segPathToNode,
|
||||||
scale: factor,
|
scale: factor,
|
||||||
|
theme: sceneInfra._theme,
|
||||||
})
|
})
|
||||||
_profileStart.layers.set(SKETCH_LAYER)
|
_profileStart.layers.set(SKETCH_LAYER)
|
||||||
_profileStart.traverse((child) => {
|
_profileStart.traverse((child) => {
|
||||||
@ -406,6 +408,7 @@ export class SceneEntities {
|
|||||||
isDraftSegment,
|
isDraftSegment,
|
||||||
scale: factor,
|
scale: factor,
|
||||||
texture: sceneInfra.extraSegmentTexture,
|
texture: sceneInfra.extraSegmentTexture,
|
||||||
|
theme: sceneInfra._theme,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
seg = straightSegment({
|
seg = straightSegment({
|
||||||
@ -417,6 +420,7 @@ export class SceneEntities {
|
|||||||
scale: factor,
|
scale: factor,
|
||||||
callExpName,
|
callExpName,
|
||||||
texture: sceneInfra.extraSegmentTexture,
|
texture: sceneInfra.extraSegmentTexture,
|
||||||
|
theme: sceneInfra._theme,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
seg.layers.set(SKETCH_LAYER)
|
seg.layers.set(SKETCH_LAYER)
|
||||||
@ -1503,7 +1507,10 @@ export class SceneEntities {
|
|||||||
const isSelected = parent?.userData?.isSelected
|
const isSelected = parent?.userData?.isSelected
|
||||||
colorSegment(
|
colorSegment(
|
||||||
selected,
|
selected,
|
||||||
isSelected ? 0x0000ff : parent?.userData?.baseColor || 0xffffff
|
isSelected
|
||||||
|
? 0x0000ff
|
||||||
|
: parent?.userData?.baseColor ||
|
||||||
|
getThemeColorForThreeJs(sceneInfra._theme)
|
||||||
)
|
)
|
||||||
const extraSegmentGroup = parent?.getObjectByName(EXTRA_SEGMENT_HANDLE)
|
const extraSegmentGroup = parent?.getObjectByName(EXTRA_SEGMENT_HANDLE)
|
||||||
if (extraSegmentGroup) {
|
if (extraSegmentGroup) {
|
||||||
|
@ -30,6 +30,7 @@ import { CameraControls } from './CameraControls'
|
|||||||
import { EngineCommandManager } from 'lang/std/engineConnection'
|
import { EngineCommandManager } from 'lang/std/engineConnection'
|
||||||
import { settings } from 'lib/settings/initialSettings'
|
import { settings } from 'lib/settings/initialSettings'
|
||||||
import { MouseState } from 'machines/modelingMachine'
|
import { MouseState } from 'machines/modelingMachine'
|
||||||
|
import { Themes } from 'lib/theme'
|
||||||
|
|
||||||
type SendType = ReturnType<typeof useModelingContext>['send']
|
type SendType = ReturnType<typeof useModelingContext>['send']
|
||||||
|
|
||||||
@ -101,6 +102,7 @@ export class SceneInfra {
|
|||||||
isFovAnimationInProgress = false
|
isFovAnimationInProgress = false
|
||||||
_baseUnit: BaseUnit = 'mm'
|
_baseUnit: BaseUnit = 'mm'
|
||||||
_baseUnitMultiplier = 1
|
_baseUnitMultiplier = 1
|
||||||
|
_theme: Themes = Themes.System
|
||||||
extraSegmentTexture: Texture
|
extraSegmentTexture: Texture
|
||||||
lastMouseState: MouseState = { type: 'idle' }
|
lastMouseState: MouseState = { type: 'idle' }
|
||||||
onDragStartCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
onDragStartCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
||||||
@ -137,6 +139,9 @@ export class SceneInfra {
|
|||||||
this._baseUnitMultiplier
|
this._baseUnitMultiplier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
set theme(theme: Themes) {
|
||||||
|
this._theme = theme
|
||||||
|
}
|
||||||
resetMouseListeners = () => {
|
resetMouseListeners = () => {
|
||||||
this.setCallbacks({
|
this.setCallbacks({
|
||||||
onDragStart: () => {},
|
onDragStart: () => {},
|
||||||
|
@ -37,22 +37,26 @@ import {
|
|||||||
} from './sceneEntities'
|
} from './sceneEntities'
|
||||||
import { getTangentPointFromPreviousArc } from 'lib/utils2d'
|
import { getTangentPointFromPreviousArc } from 'lib/utils2d'
|
||||||
import { ARROWHEAD } from './sceneInfra'
|
import { ARROWHEAD } from './sceneInfra'
|
||||||
|
import { Themes, getThemeColorForThreeJs } from 'lib/theme'
|
||||||
|
|
||||||
export function profileStart({
|
export function profileStart({
|
||||||
from,
|
from,
|
||||||
id,
|
id,
|
||||||
pathToNode,
|
pathToNode,
|
||||||
scale = 1,
|
scale = 1,
|
||||||
|
theme,
|
||||||
}: {
|
}: {
|
||||||
from: Coords2d
|
from: Coords2d
|
||||||
id: string
|
id: string
|
||||||
pathToNode: PathToNode
|
pathToNode: PathToNode
|
||||||
scale?: number
|
scale?: number
|
||||||
|
theme: Themes
|
||||||
}) {
|
}) {
|
||||||
const group = new Group()
|
const group = new Group()
|
||||||
|
|
||||||
const geometry = new BoxGeometry(12, 12, 12) // in pixels scaled later
|
const geometry = new BoxGeometry(12, 12, 12) // in pixels scaled later
|
||||||
const body = new MeshBasicMaterial({ color: 0xffffff })
|
const baseColor = getThemeColorForThreeJs(theme)
|
||||||
|
const body = new MeshBasicMaterial({ color: baseColor })
|
||||||
const mesh = new Mesh(geometry, body)
|
const mesh = new Mesh(geometry, body)
|
||||||
|
|
||||||
group.add(mesh)
|
group.add(mesh)
|
||||||
@ -79,6 +83,7 @@ export function straightSegment({
|
|||||||
scale = 1,
|
scale = 1,
|
||||||
callExpName,
|
callExpName,
|
||||||
texture,
|
texture,
|
||||||
|
theme,
|
||||||
}: {
|
}: {
|
||||||
from: Coords2d
|
from: Coords2d
|
||||||
to: Coords2d
|
to: Coords2d
|
||||||
@ -88,6 +93,7 @@ export function straightSegment({
|
|||||||
scale?: number
|
scale?: number
|
||||||
callExpName: string
|
callExpName: string
|
||||||
texture: Texture
|
texture: Texture
|
||||||
|
theme: Themes
|
||||||
}): Group {
|
}): Group {
|
||||||
const group = new Group()
|
const group = new Group()
|
||||||
|
|
||||||
@ -111,7 +117,8 @@ export function straightSegment({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseColor = callExpName === 'close' ? 0x444444 : 0xffffff
|
const baseColor =
|
||||||
|
callExpName === 'close' ? 0x444444 : getThemeColorForThreeJs(theme)
|
||||||
const body = new MeshBasicMaterial({ color: baseColor })
|
const body = new MeshBasicMaterial({ color: baseColor })
|
||||||
const mesh = new Mesh(geometry, body)
|
const mesh = new Mesh(geometry, body)
|
||||||
mesh.userData.type = isDraftSegment
|
mesh.userData.type = isDraftSegment
|
||||||
@ -134,7 +141,7 @@ export function straightSegment({
|
|||||||
const length = Math.sqrt(
|
const length = Math.sqrt(
|
||||||
Math.pow(to[0] - from[0], 2) + Math.pow(to[1] - from[1], 2)
|
Math.pow(to[0] - from[0], 2) + Math.pow(to[1] - from[1], 2)
|
||||||
)
|
)
|
||||||
const arrowGroup = createArrowhead(scale)
|
const arrowGroup = createArrowhead(scale, theme)
|
||||||
arrowGroup.position.set(to[0], to[1], 0)
|
arrowGroup.position.set(to[0], to[1], 0)
|
||||||
const dir = new Vector3()
|
const dir = new Vector3()
|
||||||
.subVectors(new Vector3(to[0], to[1], 0), new Vector3(from[0], from[1], 0))
|
.subVectors(new Vector3(to[0], to[1], 0), new Vector3(from[0], from[1], 0))
|
||||||
@ -147,7 +154,7 @@ export function straightSegment({
|
|||||||
group.add(mesh)
|
group.add(mesh)
|
||||||
if (callExpName !== 'close') group.add(arrowGroup)
|
if (callExpName !== 'close') group.add(arrowGroup)
|
||||||
|
|
||||||
const extraSegmentGroup = createExtraSegmentHandle(scale, texture)
|
const extraSegmentGroup = createExtraSegmentHandle(scale, texture, theme)
|
||||||
const offsetFromBase = new Vector2(to[0] - from[0], to[1] - from[1])
|
const offsetFromBase = new Vector2(to[0] - from[0], to[1] - from[1])
|
||||||
.normalize()
|
.normalize()
|
||||||
.multiplyScalar(EXTRA_SEGMENT_OFFSET_PX * scale)
|
.multiplyScalar(EXTRA_SEGMENT_OFFSET_PX * scale)
|
||||||
@ -162,8 +169,10 @@ export function straightSegment({
|
|||||||
return group
|
return group
|
||||||
}
|
}
|
||||||
|
|
||||||
function createArrowhead(scale = 1): Group {
|
function createArrowhead(scale = 1, theme: Themes): Group {
|
||||||
const arrowMaterial = new MeshBasicMaterial({ color: 0xffffff })
|
const arrowMaterial = new MeshBasicMaterial({
|
||||||
|
color: getThemeColorForThreeJs(theme),
|
||||||
|
})
|
||||||
// specify the size of the geometry in pixels (i.e. cone height = 20px, cone radius = 4.5px)
|
// specify the size of the geometry in pixels (i.e. cone height = 20px, cone radius = 4.5px)
|
||||||
// we'll scale the group to the correct size later to match these sizes in screen space
|
// we'll scale the group to the correct size later to match these sizes in screen space
|
||||||
const arrowheadMesh = new Mesh(new ConeGeometry(4.5, 20, 12), arrowMaterial)
|
const arrowheadMesh = new Mesh(new ConeGeometry(4.5, 20, 12), arrowMaterial)
|
||||||
@ -179,7 +188,11 @@ function createArrowhead(scale = 1): Group {
|
|||||||
return arrowGroup
|
return arrowGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
function createExtraSegmentHandle(scale: number, texture: Texture): Group {
|
function createExtraSegmentHandle(
|
||||||
|
scale: number,
|
||||||
|
texture: Texture,
|
||||||
|
theme: Themes
|
||||||
|
): Group {
|
||||||
const particleMaterial = new PointsMaterial({
|
const particleMaterial = new PointsMaterial({
|
||||||
size: 12, // in pixels
|
size: 12, // in pixels
|
||||||
map: texture,
|
map: texture,
|
||||||
@ -189,7 +202,7 @@ function createExtraSegmentHandle(scale: number, texture: Texture): Group {
|
|||||||
})
|
})
|
||||||
const mat = new MeshBasicMaterial({
|
const mat = new MeshBasicMaterial({
|
||||||
transparent: true,
|
transparent: true,
|
||||||
color: 0xffffff,
|
color: getThemeColorForThreeJs(theme),
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
})
|
})
|
||||||
const particleGeometry = new BufferGeometry().setFromPoints([
|
const particleGeometry = new BufferGeometry().setFromPoints([
|
||||||
@ -218,6 +231,7 @@ export function tangentialArcToSegment({
|
|||||||
isDraftSegment,
|
isDraftSegment,
|
||||||
scale = 1,
|
scale = 1,
|
||||||
texture,
|
texture,
|
||||||
|
theme,
|
||||||
}: {
|
}: {
|
||||||
prevSegment: SketchGroup['value'][number]
|
prevSegment: SketchGroup['value'][number]
|
||||||
from: Coords2d
|
from: Coords2d
|
||||||
@ -227,6 +241,7 @@ export function tangentialArcToSegment({
|
|||||||
isDraftSegment?: boolean
|
isDraftSegment?: boolean
|
||||||
scale?: number
|
scale?: number
|
||||||
texture: Texture
|
texture: Texture
|
||||||
|
theme: Themes
|
||||||
}): Group {
|
}): Group {
|
||||||
const group = new Group()
|
const group = new Group()
|
||||||
|
|
||||||
@ -257,7 +272,8 @@ export function tangentialArcToSegment({
|
|||||||
scale,
|
scale,
|
||||||
})
|
})
|
||||||
|
|
||||||
const body = new MeshBasicMaterial({ color: 0xffffff })
|
const baseColor = getThemeColorForThreeJs(theme)
|
||||||
|
const body = new MeshBasicMaterial({ color: baseColor })
|
||||||
const mesh = new Mesh(geometry, body)
|
const mesh = new Mesh(geometry, body)
|
||||||
mesh.userData.type = isDraftSegment
|
mesh.userData.type = isDraftSegment
|
||||||
? TANGENTIAL_ARC_TO__SEGMENT_DASH
|
? TANGENTIAL_ARC_TO__SEGMENT_DASH
|
||||||
@ -271,10 +287,11 @@ export function tangentialArcToSegment({
|
|||||||
prevSegment,
|
prevSegment,
|
||||||
pathToNode,
|
pathToNode,
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
|
baseColor,
|
||||||
}
|
}
|
||||||
group.name = TANGENTIAL_ARC_TO_SEGMENT
|
group.name = TANGENTIAL_ARC_TO_SEGMENT
|
||||||
|
|
||||||
const arrowGroup = createArrowhead(scale)
|
const arrowGroup = createArrowhead(scale, theme)
|
||||||
arrowGroup.position.set(to[0], to[1], 0)
|
arrowGroup.position.set(to[0], to[1], 0)
|
||||||
const arrowheadAngle = endAngle + (Math.PI / 2) * (ccw ? 1 : -1)
|
const arrowheadAngle = endAngle + (Math.PI / 2) * (ccw ? 1 : -1)
|
||||||
arrowGroup.quaternion.setFromUnitVectors(
|
arrowGroup.quaternion.setFromUnitVectors(
|
||||||
@ -285,7 +302,7 @@ export function tangentialArcToSegment({
|
|||||||
const shouldHide = pxLength < HIDE_SEGMENT_LENGTH
|
const shouldHide = pxLength < HIDE_SEGMENT_LENGTH
|
||||||
arrowGroup.visible = !shouldHide
|
arrowGroup.visible = !shouldHide
|
||||||
|
|
||||||
const extraSegmentGroup = createExtraSegmentHandle(scale, texture)
|
const extraSegmentGroup = createExtraSegmentHandle(scale, texture, theme)
|
||||||
const circumferenceInPx = (2 * Math.PI * radius) / scale
|
const circumferenceInPx = (2 * Math.PI * radius) / scale
|
||||||
const extraSegmentAngleDelta =
|
const extraSegmentAngleDelta =
|
||||||
(EXTRA_SEGMENT_OFFSET_PX / circumferenceInPx) * Math.PI * 2
|
(EXTRA_SEGMENT_OFFSET_PX / circumferenceInPx) * Math.PI * 2
|
||||||
|
@ -4,10 +4,8 @@ import { type IndexLoaderData } from 'lib/types'
|
|||||||
import ProjectSidebarMenu from './ProjectSidebarMenu'
|
import ProjectSidebarMenu from './ProjectSidebarMenu'
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
import styles from './AppHeader.module.css'
|
import styles from './AppHeader.module.css'
|
||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
|
||||||
import { ActionButton } from 'components/ActionButton'
|
|
||||||
import usePlatform from 'hooks/usePlatform'
|
|
||||||
import { RefreshButton } from 'components/RefreshButton'
|
import { RefreshButton } from 'components/RefreshButton'
|
||||||
|
import { CommandBarOpenButton } from './CommandBarOpenButton'
|
||||||
|
|
||||||
interface AppHeaderProps extends React.PropsWithChildren {
|
interface AppHeaderProps extends React.PropsWithChildren {
|
||||||
showToolbar?: boolean
|
showToolbar?: boolean
|
||||||
@ -23,8 +21,6 @@ export const AppHeader = ({
|
|||||||
className = '',
|
className = '',
|
||||||
enableMenu = false,
|
enableMenu = false,
|
||||||
}: AppHeaderProps) => {
|
}: AppHeaderProps) => {
|
||||||
const platform = usePlatform()
|
|
||||||
const { commandBarSend } = useCommandsContext()
|
|
||||||
const { auth } = useSettingsAuthContext()
|
const { auth } = useSettingsAuthContext()
|
||||||
const user = auth?.context?.user
|
const user = auth?.context?.user
|
||||||
|
|
||||||
@ -44,25 +40,13 @@ export const AppHeader = ({
|
|||||||
/>
|
/>
|
||||||
{/* Toolbar if the context deems it */}
|
{/* Toolbar if the context deems it */}
|
||||||
<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">
|
<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 ? (
|
{showToolbar && <Toolbar />}
|
||||||
<Toolbar />
|
|
||||||
) : (
|
|
||||||
<ActionButton
|
|
||||||
Element="button"
|
|
||||||
onClick={() => commandBarSend({ type: 'Open' })}
|
|
||||||
className="text-sm self-center flex items-center w-fit gap-3"
|
|
||||||
>
|
|
||||||
Command Palette{' '}
|
|
||||||
<kbd className="bg-primary/10 dark:bg-chalkboard-100 dark:text-primary inline-block px-1 py-0.5 border-primary dark:border-chalkboard-90">
|
|
||||||
{platform === 'macos' ? '⌘K' : 'Ctrl+/'}
|
|
||||||
</kbd>
|
|
||||||
</ActionButton>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1 py-1 ml-auto">
|
<div className="flex items-center gap-1 py-1 ml-auto">
|
||||||
{/* If there are children, show them, otherwise show User menu */}
|
{/* If there are children, show them, otherwise show User menu */}
|
||||||
{children || (
|
{children || (
|
||||||
<>
|
<>
|
||||||
|
<CommandBarOpenButton />
|
||||||
<RefreshButton />
|
<RefreshButton />
|
||||||
<UserSidebarMenu user={user} />
|
<UserSidebarMenu user={user} />
|
||||||
</>
|
</>
|
||||||
|
19
src/components/CommandBarOpenButton.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
|
import usePlatform from 'hooks/usePlatform'
|
||||||
|
|
||||||
|
export function CommandBarOpenButton() {
|
||||||
|
const { commandBarSend } = useCommandsContext()
|
||||||
|
const platform = usePlatform()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className="group rounded-full flex items-center justify-center gap-2 px-2 py-1 bg-primary/10 dark:bg-chalkboard-90 dark:backdrop-blur-sm border-primary hover:border-primary dark:border-chalkboard-50 dark:hover:border-inherit text-primary dark:text-inherit"
|
||||||
|
onClick={() => commandBarSend({ type: 'Open' })}
|
||||||
|
>
|
||||||
|
<span>Commands</span>
|
||||||
|
<kbd className="bg-primary/10 dark:bg-chalkboard-80 dark:group-hover:bg-primary font-mono rounded-sm dark:text-inherit inline-block px-1 border-primary dark:border-chalkboard-90">
|
||||||
|
{platform === 'macos' ? '⌘K' : '^/'}
|
||||||
|
</kbd>
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
@ -38,7 +38,7 @@ function CommandComboBox({
|
|||||||
<div className="flex items-center gap-2 px-4 pb-2 border-solid border-0 border-b border-b-chalkboard-20 dark:border-b-chalkboard-80">
|
<div className="flex items-center gap-2 px-4 pb-2 border-solid border-0 border-b border-b-chalkboard-20 dark:border-b-chalkboard-80">
|
||||||
<CustomIcon
|
<CustomIcon
|
||||||
name="search"
|
name="search"
|
||||||
className="w-5 h-5 bg-primary/10 text-primary"
|
className="w-5 h-5 bg-primary/10 dark:bg-primary text-primary dark:text-inherit"
|
||||||
/>
|
/>
|
||||||
<Combobox.Input
|
<Combobox.Input
|
||||||
onChange={(event) => setQuery(event.target.value)}
|
onChange={(event) => setQuery(event.target.value)}
|
||||||
|
@ -134,6 +134,10 @@ export const SettingsAuthProviderBase = ({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
setClientTheme: (context) => {
|
||||||
|
const opposingTheme = getOppositeTheme(context.app.theme.current)
|
||||||
|
sceneInfra.theme = opposingTheme
|
||||||
|
},
|
||||||
setEngineEdges: (context) => {
|
setEngineEdges: (context) => {
|
||||||
engineCommandManager.sendSceneCommand({
|
engineCommandManager.sendSceneCommand({
|
||||||
cmd_id: uuidv4(),
|
cmd_id: uuidv4(),
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
import useResizeObserver from '@react-hook/resize-observer'
|
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
|
|
||||||
interface Rect {
|
|
||||||
top: number
|
|
||||||
left: number
|
|
||||||
height: number
|
|
||||||
width: number
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes an element id and uses React refs to create a CSS clip-path rule to apply to a backdrop element
|
|
||||||
* which excludes the element with the given id, creating a "highlight" effect.
|
|
||||||
* @param highlightId
|
|
||||||
*/
|
|
||||||
export function useBackdropHighlight(target: string): string {
|
|
||||||
const [clipPath, setClipPath] = useState('')
|
|
||||||
const [elem, setElem] = useState(document.getElementById(target))
|
|
||||||
|
|
||||||
// Build the actual clip path string, cutting out the target element
|
|
||||||
function buildClipPath({ top, left, height, width }: Rect) {
|
|
||||||
const windowWidth = window.innerWidth
|
|
||||||
const windowHeight = window.innerHeight
|
|
||||||
|
|
||||||
return `
|
|
||||||
path(evenodd, "M0 0 l${windowWidth} 0 l0 ${windowHeight} l-${windowWidth} 0 Z \
|
|
||||||
M${left} ${top} l${width} 0 l0 ${height} l-${width} 0 Z")
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
// initial setup of clip path
|
|
||||||
useEffect(() => {
|
|
||||||
if (!elem) {
|
|
||||||
const newElem = document.getElementById(target)
|
|
||||||
if (newElem === null) {
|
|
||||||
throw new Error(
|
|
||||||
`Could not find element with id "${target}" to highlight`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
setElem(document.getElementById(target))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const { top, left, height, width } = elem.getBoundingClientRect()
|
|
||||||
setClipPath(buildClipPath({ top, left, height, width }))
|
|
||||||
}, [elem, target])
|
|
||||||
|
|
||||||
// update clip path on resize
|
|
||||||
useResizeObserver(elem, (entry) => {
|
|
||||||
const { height, width } = entry.contentRect
|
|
||||||
// the top and left are relative to the viewport, so we need to get the target's position
|
|
||||||
const { top, left } = entry.target.getBoundingClientRect()
|
|
||||||
setClipPath(buildClipPath({ top, left, height, width }))
|
|
||||||
})
|
|
||||||
|
|
||||||
return clipPath
|
|
||||||
}
|
|
@ -14,8 +14,8 @@ export function useEngineConnectionSubscriptions() {
|
|||||||
event: 'highlight_set_entity',
|
event: 'highlight_set_entity',
|
||||||
callback: ({ data }) => {
|
callback: ({ data }) => {
|
||||||
if (data?.entity_id) {
|
if (data?.entity_id) {
|
||||||
const sourceRange =
|
const sourceRange = engineCommandManager.artifactMap?.[data.entity_id]
|
||||||
engineCommandManager.artifactMap?.[data.entity_id]?.range
|
?.range || [0, 0]
|
||||||
editorManager.setHighlightRange(sourceRange)
|
editorManager.setHighlightRange(sourceRange)
|
||||||
} else if (
|
} else if (
|
||||||
!editorManager.highlightRange ||
|
!editorManager.highlightRange ||
|
||||||
|
@ -542,6 +542,27 @@ class EngineConnection {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
this.unreliableDataChannel.addEventListener('message', (event) => {
|
||||||
|
const result: UnreliableResponses = JSON.parse(event.data)
|
||||||
|
Object.values(
|
||||||
|
this.engineCommandManager.unreliableSubscriptions[result.type] || {}
|
||||||
|
).forEach(
|
||||||
|
// TODO: There is only one response that uses the unreliable channel atm,
|
||||||
|
// highlight_set_entity, if there are more it's likely they will all have the same
|
||||||
|
// sequence logic, but I'm not sure if we use a single global sequence or a sequence
|
||||||
|
// per unreliable subscription.
|
||||||
|
(callback) => {
|
||||||
|
if (
|
||||||
|
result.type === 'highlight_set_entity' &&
|
||||||
|
result?.data?.sequence &&
|
||||||
|
result?.data.sequence > this.engineCommandManager.inSequence
|
||||||
|
) {
|
||||||
|
this.engineCommandManager.inSequence = result.data.sequence
|
||||||
|
callback(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -853,7 +874,7 @@ type CommandTypes = Models['ModelingCmd_type']['type'] | 'batch'
|
|||||||
|
|
||||||
type UnreliableResponses = Extract<
|
type UnreliableResponses = Extract<
|
||||||
Models['OkModelingCmdResponse_type'],
|
Models['OkModelingCmdResponse_type'],
|
||||||
{ type: 'highlight_set_entity' }
|
{ type: 'highlight_set_entity' | 'camera_drag_move' }
|
||||||
>
|
>
|
||||||
interface UnreliableSubscription<T extends UnreliableResponses['type']> {
|
interface UnreliableSubscription<T extends UnreliableResponses['type']> {
|
||||||
event: T
|
event: T
|
||||||
@ -1061,32 +1082,6 @@ export class EngineCommandManager {
|
|||||||
setIsStreamReady(false)
|
setIsStreamReady(false)
|
||||||
},
|
},
|
||||||
onConnectionStarted: (engineConnection) => {
|
onConnectionStarted: (engineConnection) => {
|
||||||
engineConnection?.pc?.addEventListener('datachannel', (event) => {
|
|
||||||
let unreliableDataChannel = event.channel
|
|
||||||
|
|
||||||
unreliableDataChannel.addEventListener('message', (event) => {
|
|
||||||
const result: UnreliableResponses = JSON.parse(event.data)
|
|
||||||
Object.values(
|
|
||||||
this.unreliableSubscriptions[result.type] || {}
|
|
||||||
).forEach(
|
|
||||||
// TODO: There is only one response that uses the unreliable channel atm,
|
|
||||||
// highlight_set_entity, if there are more it's likely they will all have the same
|
|
||||||
// sequence logic, but I'm not sure if we use a single global sequence or a sequence
|
|
||||||
// per unreliable subscription.
|
|
||||||
(callback) => {
|
|
||||||
if (
|
|
||||||
result?.data?.sequence &&
|
|
||||||
result?.data.sequence > this.inSequence &&
|
|
||||||
result.type === 'highlight_set_entity'
|
|
||||||
) {
|
|
||||||
this.inSequence = result.data.sequence
|
|
||||||
callback(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// When the EngineConnection starts a connection, we want to register
|
// When the EngineConnection starts a connection, we want to register
|
||||||
// callbacks into the WebSocket/PeerConnection.
|
// callbacks into the WebSocket/PeerConnection.
|
||||||
engineConnection.websocket?.addEventListener('message', (event) => {
|
engineConnection.websocket?.addEventListener('message', (event) => {
|
||||||
@ -1366,14 +1361,11 @@ export class EngineCommandManager {
|
|||||||
callback,
|
callback,
|
||||||
}: Subscription<T>): () => void {
|
}: Subscription<T>): () => void {
|
||||||
const localUnsubscribeId = uuidv4()
|
const localUnsubscribeId = uuidv4()
|
||||||
const otherEventCallbacks = this.subscriptions[event]
|
if (!this.subscriptions[event]) {
|
||||||
if (otherEventCallbacks) {
|
this.subscriptions[event] = {}
|
||||||
otherEventCallbacks[localUnsubscribeId] = callback
|
|
||||||
} else {
|
|
||||||
this.subscriptions[event] = {
|
|
||||||
[localUnsubscribeId]: callback,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
this.subscriptions[event][localUnsubscribeId] = callback
|
||||||
|
|
||||||
return () => this.unSubscribeTo(event, localUnsubscribeId)
|
return () => this.unSubscribeTo(event, localUnsubscribeId)
|
||||||
}
|
}
|
||||||
private unSubscribeTo(event: ModelTypes, id: string) {
|
private unSubscribeTo(event: ModelTypes, id: string) {
|
||||||
@ -1384,14 +1376,10 @@ export class EngineCommandManager {
|
|||||||
callback,
|
callback,
|
||||||
}: UnreliableSubscription<T>): () => void {
|
}: UnreliableSubscription<T>): () => void {
|
||||||
const localUnsubscribeId = uuidv4()
|
const localUnsubscribeId = uuidv4()
|
||||||
const otherEventCallbacks = this.unreliableSubscriptions[event]
|
if (!this.unreliableSubscriptions[event]) {
|
||||||
if (otherEventCallbacks) {
|
this.unreliableSubscriptions[event] = {}
|
||||||
otherEventCallbacks[localUnsubscribeId] = callback
|
|
||||||
} else {
|
|
||||||
this.unreliableSubscriptions[event] = {
|
|
||||||
[localUnsubscribeId]: callback,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
this.unreliableSubscriptions[event][localUnsubscribeId] = callback
|
||||||
return () => this.unSubscribeToUnreliable(event, localUnsubscribeId)
|
return () => this.unSubscribeToUnreliable(event, localUnsubscribeId)
|
||||||
}
|
}
|
||||||
private unSubscribeToUnreliable(
|
private unSubscribeToUnreliable(
|
||||||
|
@ -65,3 +65,15 @@ export function getThemeColorForEngine(theme: Themes) {
|
|||||||
? { r: dark, g: dark, b: dark, a: 1 }
|
? { r: dark, g: dark, b: dark, a: 1 }
|
||||||
: { r: light, g: light, b: light, a: 1 }
|
: { r: light, g: light, b: light, a: 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ThreeJS uses hex values for colors
|
||||||
|
* @param theme
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function getThemeColorForThreeJs(theme: Themes) {
|
||||||
|
const resolvedTheme = getResolvedTheme(theme)
|
||||||
|
const dark = 0x1c1c1c
|
||||||
|
const light = 0xf9f9f9
|
||||||
|
return resolvedTheme === Themes.Dark ? dark : light
|
||||||
|
}
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
|
|
||||||
export const settingsMachine = createMachine(
|
export const settingsMachine = createMachine(
|
||||||
{
|
{
|
||||||
/** @xstate-layout N4IgpgJg5mDOIC5QGUwBc0EsB2VYDpMIAbMAYlnXwFsB7CMYnKfAV20zVgG0AGAXUSgADrVidMtbEJAAPRABYAHAFZ8vAEwA2FVq0aNAZgCcARl0B2ADQgAnolO8LvfBYUXT+48YW+tCgF8Am1QMZgIiUgoqAENhYXw0AAswajA+QSQQUXEsKRl5BCM1DQUDMo0VQwVjJxt7BFMDJXwNWo0LFSU3c0DgkFCsXAiScgAlOHQAAkow4YyZHIl8rMKAWn18Q39q3ScVFQ1NFXqHXiVTfGNqhSdeXi1DJQ1TIJD0IbxCUbIAKgWsks8tJVopjFp8KZjEpqi9lKZDE0TnYzgZXO5PG0fH4+u85l9IuRQlMYsRiFNsGAAO4zD7hAEiMTLEGgda6fAKJoIiyIkwWYwWawoxpGFxaHkKFS1a7woL9bD0OAyQbhRZM4EFRBrUyOLY7SVafaHTSnBDGDqQiz6DRKbwqTxvAZ04bfUhq3KSFlyBxHdQIhR6HTQmoC02OUwKPW7GrPdy8QxygJAA */
|
/** @xstate-layout N4IgpgJg5mDOIC5QGUwBc0EsB2VYDpMIAbMAYlnXwEMAHW-Ae2wCNHqAnCHKZNatAFdYAbQAMAXUShajWJizNpIAB6IAbAFZN+AOwAWAIwAOYwE4AzGYBM+-ZosAaEAE9Eh62LP51ls+v0LMWt1awMAX3DnVAweAiJSCio6BjQACzAAWzAAYUZiRg5xKSQQWXlFbGU1BA9vQ0N1CwCxdVbdY1DnNwQzPp8zTTFje1D1QwtjSOj0LFx4knJKNHxMxggwYh58DYAzakFiNABVbAVi5XKFTCVSmotNY3w7YysHRuNDTXV1bvdG7w-IKTcbaazWCzTEAxOZ4QiLJIrFL4dJZMAXUpXSrVDTGazPMQPR4GXRBAx-XoGfDWIadMx4n6EqEwuLwxLLVbrTbbNKYKBpLb8tAAUWgcAxMjk11uoHumn0+DEw2sJkMulCgWsFL6YnwfX0ELsYg61jMumZs1ZCXIACU4OgAATLWGiSSXKXYu4aLz4UwWBr6DqBYYUzSePXqUlBLxmyZmC2xeZs8gxB3UYjEJ2W+YSsoem5VL0IKy6z6EsJifQ2Czq0MTHzq8Yjfz6MQmBMu5NkABUuaxBZxCDD+DD5lJgUjxssFP0xl0I+0pm06uMmg8kSiIGwXPgpRZ83dFQHRYAtA0LCO2tZjGIHJNdB5fq5EK3dc1OsNGkrA+oO1bFoe0qFrKiAnlol7BDed5zo+FK+Doc7qhCNaVv4UwbkAA */
|
||||||
id: 'Settings',
|
id: 'Settings',
|
||||||
predictableActionArguments: true,
|
predictableActionArguments: true,
|
||||||
context: {} as ReturnType<typeof createSettings>,
|
context: {} as ReturnType<typeof createSettings>,
|
||||||
@ -59,6 +59,7 @@ export const settingsMachine = createMachine(
|
|||||||
'setThemeClass',
|
'setThemeClass',
|
||||||
'setEngineTheme',
|
'setEngineTheme',
|
||||||
'persistSettings',
|
'persistSettings',
|
||||||
|
'setClientTheme',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -83,6 +84,7 @@ export const settingsMachine = createMachine(
|
|||||||
'setClientSideSceneUnits',
|
'setClientSideSceneUnits',
|
||||||
'Execute AST',
|
'Execute AST',
|
||||||
'persistSettings',
|
'persistSettings',
|
||||||
|
'setClientTheme',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -96,6 +98,7 @@ export const settingsMachine = createMachine(
|
|||||||
'setClientSideSceneUnits',
|
'setClientSideSceneUnits',
|
||||||
'Execute AST',
|
'Execute AST',
|
||||||
'persistSettings',
|
'persistSettings',
|
||||||
|
'setClientTheme',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
import { useStore } from '../../useStore'
|
||||||
import { useBackdropHighlight } from 'hooks/useBackdropHighlight'
|
|
||||||
|
|
||||||
export default function CodeEditor() {
|
export default function CodeEditor() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { buttonDownInStream } = useStore((s) => ({
|
||||||
@ -12,14 +11,6 @@ export default function CodeEditor() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-end items-center inset-0 z-50 pointer-events-none">
|
<div className="fixed grid justify-end items-center inset-0 z-50 pointer-events-none">
|
||||||
<div
|
|
||||||
className="fixed inset-0 bg-black opacity-50 dark:opacity-80 pointer-events-none"
|
|
||||||
style={
|
|
||||||
{
|
|
||||||
/*clipPath: useBackdropHighlight('code-pane')*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
></div>
|
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-3/4 flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-3/4 flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { OnboardingButtons, kbdClasses, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, kbdClasses, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
import { useStore } from '../../useStore'
|
||||||
import { useBackdropHighlight } from 'hooks/useBackdropHighlight'
|
|
||||||
import { bracketWidthConstantLine } from 'lib/exampleKcl'
|
import { bracketWidthConstantLine } from 'lib/exampleKcl'
|
||||||
|
|
||||||
export default function InteractiveNumbers() {
|
export default function InteractiveNumbers() {
|
||||||
@ -13,14 +12,6 @@ export default function InteractiveNumbers() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-end items-center inset-0 z-50 pointer-events-none">
|
<div className="fixed grid justify-end items-center inset-0 z-50 pointer-events-none">
|
||||||
<div
|
|
||||||
className="fixed inset-0 bg-black opacity-50 pointer-events-none"
|
|
||||||
style={
|
|
||||||
{
|
|
||||||
/*clipPath: useBackdropHighlight('code-pane')*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
></div>
|
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-3/4 flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-3/4 flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
import { useStore } from '../../useStore'
|
||||||
import { useBackdropHighlight } from 'hooks/useBackdropHighlight'
|
|
||||||
import { Themes, getSystemTheme } from 'lib/theme'
|
import { Themes, getSystemTheme } from 'lib/theme'
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
import { bracketThicknessCalculationLine } from 'lib/exampleKcl'
|
import { bracketThicknessCalculationLine } from 'lib/exampleKcl'
|
||||||
@ -29,14 +28,6 @@ export default function ParametricModeling() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed grid justify-end items-center inset-0 z-50 pointer-events-none">
|
<div className="fixed grid justify-end items-center inset-0 z-50 pointer-events-none">
|
||||||
<div
|
|
||||||
className="fixed inset-0 bg-black dark:bg-black-80 opacity-50 pointer-events-none"
|
|
||||||
style={
|
|
||||||
{
|
|
||||||
/*clipPath: useBackdropHighlight('code-pane')*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
></div>
|
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-3/4 flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-3/4 flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
|
16
src/wasm-lib/Cargo.lock
generated
@ -2048,9 +2048,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad-modeling-cmds"
|
name = "kittycad-modeling-cmds"
|
||||||
version = "0.2.23"
|
version = "0.2.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c1f8bdab7f09b4f4a954dafe0694e96f6f2b73733cf7cddccc42ee493e2c1e9"
|
checksum = "c390a9f643aa00d2c3ffe880f1810066f52a13877ec3ecab858ff53cad84bd5e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -2841,9 +2841,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.81"
|
version = "1.0.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
|
checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@ -3519,9 +3519,9 @@ checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.200"
|
version = "1.0.201"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f"
|
checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
@ -3537,9 +3537,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.200"
|
version = "1.0.201"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb"
|
checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -66,7 +66,7 @@ kittycad = { version = "0.3.1", default-features = false, features = ["js", "req
|
|||||||
kittycad-execution-plan = "0.1.6"
|
kittycad-execution-plan = "0.1.6"
|
||||||
kittycad-execution-plan-macros = "0.1.9"
|
kittycad-execution-plan-macros = "0.1.9"
|
||||||
kittycad-execution-plan-traits = "0.1.14"
|
kittycad-execution-plan-traits = "0.1.14"
|
||||||
kittycad-modeling-cmds = "0.2.23"
|
kittycad-modeling-cmds = "0.2.24"
|
||||||
kittycad-modeling-session = "0.1.4"
|
kittycad-modeling-session = "0.1.4"
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
|
@ -18,7 +18,7 @@ once_cell = "1.19.0"
|
|||||||
proc-macro2 = "1"
|
proc-macro2 = "1"
|
||||||
quote = "1"
|
quote = "1"
|
||||||
regex = "1.10"
|
regex = "1.10"
|
||||||
serde = { version = "1.0.200", features = ["derive"] }
|
serde = { version = "1.0.201", features = ["derive"] }
|
||||||
serde_tokenstream = "0.2"
|
serde_tokenstream = "0.2"
|
||||||
syn = { version = "2.0.61", features = ["full"] }
|
syn = { version = "2.0.61", features = ["full"] }
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ parse-display = "0.9.0"
|
|||||||
reqwest = { version = "0.11.26", default-features = false, features = ["stream", "rustls-tls"] }
|
reqwest = { version = "0.11.26", default-features = false, features = ["stream", "rustls-tls"] }
|
||||||
ropey = "1.6.1"
|
ropey = "1.6.1"
|
||||||
schemars = { version = "0.8.17", features = ["impl_json_schema", "url", "uuid1"] }
|
schemars = { version = "0.8.17", features = ["impl_json_schema", "url", "uuid1"] }
|
||||||
serde = { version = "1.0.200", features = ["derive"] }
|
serde = { version = "1.0.201", features = ["derive"] }
|
||||||
serde_json = "1.0.116"
|
serde_json = "1.0.116"
|
||||||
sha2 = "0.10.8"
|
sha2 = "0.10.8"
|
||||||
thiserror = "1.0.60"
|
thiserror = "1.0.60"
|
||||||
|