Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
26ef7218b2 | |||
e5a4fb439c | |||
97ad66a358 | |||
26438270ff | |||
a0cfda6d7a | |||
58a62b8097 | |||
e2909c509f | |||
07eaf93e78 | |||
6a5ca3088a | |||
6501072d80 | |||
726fd02bad | |||
d0f9ae475f | |||
da323e22d4 | |||
8dc3628e9b | |||
253744867b | |||
c45eb1e3e3 | |||
758aac9328 | |||
309943cf2c | |||
b3d4ab91fc | |||
5e73fa45f0 | |||
17d23a17db |
@ -19,7 +19,17 @@ abs(num: number) -> number
|
|||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const myVar = abs(-4)
|
const myAngle = -120
|
||||||
|
|
||||||
|
const sketch001 = startSketchOn('-XZ')
|
||||||
|
|> startProfileAt([0, 0], %)
|
||||||
|
|> line([8, 0], %)
|
||||||
|
|> angledLine({ angle: abs(myAngle), length: 5 }, %)
|
||||||
|
|> line([-5, 0], %)
|
||||||
|
|> angledLine({ angle: myAngle, length: 5 }, %)
|
||||||
|
|> close(%)
|
||||||
|
|
||||||
|
const baseExtrusion = extrude(5, sketch001)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Arguments
|
### Arguments
|
||||||
|
@ -31,7 +31,6 @@ layout: manual
|
|||||||
* [`fillet`](kcl/fillet)
|
* [`fillet`](kcl/fillet)
|
||||||
* [`floor`](kcl/floor)
|
* [`floor`](kcl/floor)
|
||||||
* [`getEdge`](kcl/getEdge)
|
* [`getEdge`](kcl/getEdge)
|
||||||
* [`getExtrudeWallTransform`](kcl/getExtrudeWallTransform)
|
|
||||||
* [`getNextAdjacentEdge`](kcl/getNextAdjacentEdge)
|
* [`getNextAdjacentEdge`](kcl/getNextAdjacentEdge)
|
||||||
* [`getOppositeEdge`](kcl/getOppositeEdge)
|
* [`getOppositeEdge`](kcl/getOppositeEdge)
|
||||||
* [`getPreviousAdjacentEdge`](kcl/getPreviousAdjacentEdge)
|
* [`getPreviousAdjacentEdge`](kcl/getPreviousAdjacentEdge)
|
||||||
|
@ -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
|
||||||
@ -130,6 +131,7 @@ test('Basic sketch', async ({ page }) => {
|
|||||||
// selected two lines therefore there should be two cursors
|
// selected two lines therefore there should be two cursors
|
||||||
await expect(page.locator('.cm-cursor')).toHaveCount(2)
|
await expect(page.locator('.cm-cursor')).toHaveCount(2)
|
||||||
|
|
||||||
|
await page.getByRole('button', { name: 'Constrain' }).click()
|
||||||
await page.getByRole('button', { name: 'Equal Length' }).click()
|
await page.getByRole('button', { name: 'Equal Length' }).click()
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
@ -263,6 +265,88 @@ test('Can moving camera', async ({ page, context }) => {
|
|||||||
}, [1, -94, -94])
|
}, [1, -94, -94])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('if you click the format button it formats your code', async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const u = getUtils(page)
|
||||||
|
await page.setViewportSize({ width: 1000, height: 500 })
|
||||||
|
await page.goto('/')
|
||||||
|
|
||||||
|
await u.waitForAuthSkipAppStart()
|
||||||
|
|
||||||
|
// check no error to begin with
|
||||||
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
||||||
|
|
||||||
|
await page.click('.cm-content')
|
||||||
|
await page.keyboard.type(`const part001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, -10], %)
|
||||||
|
|> line([20, 0], %)
|
||||||
|
|> line([0, 20], %)
|
||||||
|
|> line([-20, 0], %)
|
||||||
|
|> close(%)`)
|
||||||
|
await page.click('#code-pane button:first-child')
|
||||||
|
await page.click('button:has-text("Format code")')
|
||||||
|
|
||||||
|
await expect(page.locator('.cm-content'))
|
||||||
|
.toHaveText(`const part001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, -10], %)
|
||||||
|
|> line([20, 0], %)
|
||||||
|
|> line([0, 20], %)
|
||||||
|
|> line([-20, 0], %)
|
||||||
|
|> close(%)`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('if you use the format keyboard binding it formats your code', async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const u = getUtils(page)
|
||||||
|
await page.addInitScript(async () => {
|
||||||
|
localStorage.setItem(
|
||||||
|
'persistCode',
|
||||||
|
`const part001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, -10], %)
|
||||||
|
|> line([20, 0], %)
|
||||||
|
|> line([0, 20], %)
|
||||||
|
|> line([-20, 0], %)
|
||||||
|
|> close(%)`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
await page.setViewportSize({ width: 1000, height: 500 })
|
||||||
|
const lspStartPromise = page.waitForEvent('console', async (message) => {
|
||||||
|
// it would be better to wait for a message that the kcl lsp has started by looking for the message message.text().includes('[lsp] [window/logMessage]')
|
||||||
|
// but that doesn't seem to make it to the console for macos/safari :(
|
||||||
|
if (message.text().includes('start kcl lsp')) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 200))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
await page.goto('/')
|
||||||
|
await u.waitForAuthSkipAppStart()
|
||||||
|
await lspStartPromise
|
||||||
|
|
||||||
|
// check no error to begin with
|
||||||
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
||||||
|
|
||||||
|
await u.openDebugPanel()
|
||||||
|
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||||
|
await u.closeDebugPanel()
|
||||||
|
|
||||||
|
// focus the editor
|
||||||
|
await page.click('.cm-line')
|
||||||
|
|
||||||
|
// Hit alt+shift+f to format the code
|
||||||
|
await page.keyboard.press('Alt+Shift+KeyF')
|
||||||
|
|
||||||
|
await expect(page.locator('.cm-content'))
|
||||||
|
.toHaveText(`const part001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-10, -10], %)
|
||||||
|
|> line([20, 0], %)
|
||||||
|
|> line([0, 20], %)
|
||||||
|
|> line([-20, 0], %)
|
||||||
|
|> close(%)`)
|
||||||
|
})
|
||||||
|
|
||||||
test('if you write invalid kcl you get inlined errors', async ({ page }) => {
|
test('if you write invalid kcl you get inlined errors', async ({ page }) => {
|
||||||
const u = getUtils(page)
|
const u = getUtils(page)
|
||||||
await page.setViewportSize({ width: 1000, height: 500 })
|
await page.setViewportSize({ width: 1000, height: 500 })
|
||||||
@ -528,10 +612,6 @@ test.describe('Can create sketches on all planes and their back sides', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('Auto complete works', async ({ page }) => {
|
test('Auto complete works', async ({ page }) => {
|
||||||
test.skip(
|
|
||||||
true,
|
|
||||||
'CORS issue stopping the kcl lsp from working, enable again later'
|
|
||||||
)
|
|
||||||
const u = getUtils(page)
|
const u = getUtils(page)
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
await page.setViewportSize({ width: 1200, height: 500 })
|
||||||
@ -861,11 +941,14 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
|
|||||||
// click a segment hold shift and click an axis, see that a relevant constraint is enabled
|
// click a segment hold shift and click an axis, see that a relevant constraint is enabled
|
||||||
await topHorzSegmentClick()
|
await topHorzSegmentClick()
|
||||||
await page.keyboard.down('Shift')
|
await page.keyboard.down('Shift')
|
||||||
|
const constrainButton = page.getByRole('button', { name: 'Constrain' })
|
||||||
const absYButton = page.getByRole('button', { name: 'ABS Y' })
|
const absYButton = page.getByRole('button', { name: 'ABS Y' })
|
||||||
|
await constrainButton.click()
|
||||||
await expect(absYButton).toBeDisabled()
|
await expect(absYButton).toBeDisabled()
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await xAxisClick()
|
await xAxisClick()
|
||||||
await page.keyboard.up('Shift')
|
await page.keyboard.up('Shift')
|
||||||
|
await constrainButton.click()
|
||||||
await absYButton.and(page.locator(':not([disabled])')).waitFor()
|
await absYButton.and(page.locator(':not([disabled])')).waitFor()
|
||||||
await expect(absYButton).not.toBeDisabled()
|
await expect(absYButton).not.toBeDisabled()
|
||||||
|
|
||||||
@ -875,12 +958,14 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
|
|||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
// same selection but click the axis first
|
// same selection but click the axis first
|
||||||
await xAxisClick()
|
await xAxisClick()
|
||||||
|
await constrainButton.click()
|
||||||
await expect(absYButton).toBeDisabled()
|
await expect(absYButton).toBeDisabled()
|
||||||
await page.keyboard.down('Shift')
|
await page.keyboard.down('Shift')
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await topHorzSegmentClick()
|
await topHorzSegmentClick()
|
||||||
|
|
||||||
await page.keyboard.up('Shift')
|
await page.keyboard.up('Shift')
|
||||||
|
await constrainButton.click()
|
||||||
await expect(absYButton).not.toBeDisabled()
|
await expect(absYButton).not.toBeDisabled()
|
||||||
|
|
||||||
// clear selection by clicking on nothing
|
// clear selection by clicking on nothing
|
||||||
@ -889,10 +974,12 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
|
|||||||
// check the same selection again by putting cursor in code first then selecting axis
|
// check the same selection again by putting cursor in code first then selecting axis
|
||||||
await page.getByText(` |> line([-${commonPoints.num2}, 0], %)`).click()
|
await page.getByText(` |> line([-${commonPoints.num2}, 0], %)`).click()
|
||||||
await page.keyboard.down('Shift')
|
await page.keyboard.down('Shift')
|
||||||
|
await constrainButton.click()
|
||||||
await expect(absYButton).toBeDisabled()
|
await expect(absYButton).toBeDisabled()
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await xAxisClick()
|
await xAxisClick()
|
||||||
await page.keyboard.up('Shift')
|
await page.keyboard.up('Shift')
|
||||||
|
await constrainButton.click()
|
||||||
await expect(absYButton).not.toBeDisabled()
|
await expect(absYButton).not.toBeDisabled()
|
||||||
|
|
||||||
// clear selection by clicking on nothing
|
// clear selection by clicking on nothing
|
||||||
@ -954,9 +1041,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 +1351,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,
|
||||||
}) => {
|
}) => {
|
||||||
@ -1761,6 +1913,7 @@ test('Can code mod a line length', async ({ page }) => {
|
|||||||
const startXPx = 500
|
const startXPx = 500
|
||||||
await page.mouse.move(startXPx + PUR * 15, 250 - PUR * 10)
|
await page.mouse.move(startXPx + PUR * 15, 250 - PUR * 10)
|
||||||
await page.mouse.click(615, 102)
|
await page.mouse.click(615, 102)
|
||||||
|
await page.getByRole('button', { name: 'Constrain', exact: true }).click()
|
||||||
await page.getByRole('button', { name: 'length', exact: true }).click()
|
await page.getByRole('button', { name: 'length', exact: true }).click()
|
||||||
await page.getByText('Add constraining value').click()
|
await page.getByText('Add constraining value').click()
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 41 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: 45 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 33 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: 47 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 45 KiB |
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "untitled-app",
|
"name": "untitled-app",
|
||||||
"version": "0.20.2",
|
"version": "0.21.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.16.0",
|
"@codemirror/autocomplete": "^6.16.0",
|
||||||
|
126
src-tauri/Cargo.lock
generated
@ -169,9 +169,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.82"
|
version = "1.0.83"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
|
checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
]
|
]
|
||||||
@ -334,7 +334,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -369,7 +369,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -415,7 +415,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -564,7 +564,7 @@ dependencies = [
|
|||||||
"proc-macro-crate 3.1.0",
|
"proc-macro-crate 3.1.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
"syn_derive",
|
"syn_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -873,7 +873,7 @@ dependencies = [
|
|||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1075,7 +1075,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
|
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1085,7 +1085,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
|
checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1109,7 +1109,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"strsim 0.10.0",
|
"strsim 0.10.0",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1120,7 +1120,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1167,7 +1167,7 @@ checksum = "377af281d8f23663862a7c84623bc5dcf7f8c44b13c7496a590bdc157f941a43"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1204,7 +1204,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_tokenstream",
|
"serde_tokenstream",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1287,7 +1287,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1385,7 +1385,7 @@ checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1536,7 +1536,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1652,7 +1652,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1928,7 +1928,7 @@ dependencies = [
|
|||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1956,7 +1956,7 @@ dependencies = [
|
|||||||
"inflections",
|
"inflections",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2031,7 +2031,7 @@ dependencies = [
|
|||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2536,7 +2536,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kcl-lib"
|
name = "kcl-lib"
|
||||||
version = "0.1.54"
|
version = "0.1.55"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"approx",
|
"approx",
|
||||||
@ -2640,7 +2640,7 @@ checksum = "0611fc9b9786175da21d895ffa0f65039e19c9111e94a41b7af999e3b95f045f"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3362,7 +3362,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"regex-syntax 0.7.5",
|
"regex-syntax 0.7.5",
|
||||||
"structmeta 0.2.0",
|
"structmeta 0.2.0",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3376,7 +3376,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"regex-syntax 0.8.3",
|
"regex-syntax 0.8.3",
|
||||||
"structmeta 0.3.0",
|
"structmeta 0.3.0",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3518,7 +3518,7 @@ dependencies = [
|
|||||||
"phf_shared 0.11.2",
|
"phf_shared 0.11.2",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3586,7 +3586,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4424,7 +4424,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"serde_derive_internals",
|
"serde_derive_internals",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4509,9 +4509,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[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",
|
||||||
]
|
]
|
||||||
@ -4527,13 +4527,13 @@ 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",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4544,7 +4544,7 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4577,7 +4577,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4598,7 +4598,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"serde",
|
"serde",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4640,7 +4640,7 @@ dependencies = [
|
|||||||
"darling",
|
"darling",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4908,7 +4908,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"structmeta-derive 0.2.0",
|
"structmeta-derive 0.2.0",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4920,7 +4920,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"structmeta-derive 0.3.0",
|
"structmeta-derive 0.3.0",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4931,7 +4931,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4942,7 +4942,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4964,7 +4964,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4997,9 +4997,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.60"
|
version = "2.0.61"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
|
checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -5015,7 +5015,7 @@ dependencies = [
|
|||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5032,7 +5032,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5249,7 +5249,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
"tauri-utils",
|
"tauri-utils",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"time",
|
"time",
|
||||||
@ -5267,7 +5267,7 @@ dependencies = [
|
|||||||
"heck 0.4.1",
|
"heck 0.4.1",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
"tauri-codegen",
|
"tauri-codegen",
|
||||||
"tauri-utils",
|
"tauri-utils",
|
||||||
]
|
]
|
||||||
@ -5602,22 +5602,22 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.59"
|
version = "1.0.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
|
checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.59"
|
version = "1.0.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
|
checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5706,7 +5706,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5895,7 +5895,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5924,7 +5924,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -6048,7 +6048,7 @@ dependencies = [
|
|||||||
"Inflector",
|
"Inflector",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -6261,7 +6261,7 @@ dependencies = [
|
|||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -6360,7 +6360,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -6394,7 +6394,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
@ -6535,7 +6535,7 @@ checksum = "ac1345798ecd8122468840bcdf1b95e5dc6d2206c5e4b0eafa078d061f59c9bc"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -6641,7 +6641,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -6652,7 +6652,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -7094,7 +7094,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.60",
|
"syn 2.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -74,5 +74,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"productName": "Zoo Modeling App",
|
"productName": "Zoo Modeling App",
|
||||||
"version": "0.20.2"
|
"version": "0.21.2"
|
||||||
}
|
}
|
||||||
|
133
src/Toolbar.tsx
@ -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 {
|
||||||
@ -12,18 +11,18 @@ import {
|
|||||||
useNetworkStatus,
|
useNetworkStatus,
|
||||||
} from 'components/NetworkHealthIndicator'
|
} from 'components/NetworkHealthIndicator'
|
||||||
import { useStore } from 'useStore'
|
import { useStore } from 'useStore'
|
||||||
|
import { ActionButtonDropdown } from 'components/ActionButtonDropdown'
|
||||||
|
|
||||||
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)
|
||||||
const iconClassName =
|
const iconClassName =
|
||||||
'group-disabled:text-chalkboard-50 group-enabled:group-hover:!text-chalkboard-10 group-pressed:!text-chalkboard-10'
|
'group-disabled:text-chalkboard-50 group-enabled:group-hover:!text-primary dark:group-enabled:group-hover:!text-inherit group-pressed:!text-chalkboard-10 group-ui-open:!text-chalkboard-10 dark:group-ui-open:!text-chalkboard-10'
|
||||||
const bgClassName =
|
const bgClassName =
|
||||||
'group-disabled:!bg-transparent group-enabled:group-hover:bg-primary group-pressed:bg-primary'
|
'group-disabled:!bg-transparent group-enabled:group-hover:bg-primary/10 dark:group-enabled:group-hover:bg-primary group-pressed:bg-primary group-ui-open:bg-primary'
|
||||||
const buttonClassName =
|
const buttonClassName =
|
||||||
'bg-chalkboard-10 dark:bg-chalkboard-100 hover:bg-chalkboard-10 dark:hover:bg-chalkboard-100'
|
'bg-chalkboard-10 dark:bg-chalkboard-100 enabled:hover:bg-chalkboard-10 dark:enabled:hover:bg-chalkboard-100 pressed:!border-primary ui-open:!border-primary'
|
||||||
const pathId = useMemo(() => {
|
const pathId = useMemo(() => {
|
||||||
if (!isSingleCursorInPipe(context.selectionRanges, kclManager.ast)) {
|
if (!isSingleCursorInPipe(context.selectionRanges, kclManager.ast)) {
|
||||||
return false
|
return false
|
||||||
@ -59,10 +58,7 @@ export const Toolbar = () => {
|
|||||||
{...props}
|
{...props}
|
||||||
ref={toolbarButtonsRef}
|
ref={toolbarButtonsRef}
|
||||||
onWheel={handleToolbarButtonsWheelEvent}
|
onWheel={handleToolbarButtonsWheelEvent}
|
||||||
className={
|
className={'m-0 py-1 rounded-l-sm flex gap-2 items-center ' + className}
|
||||||
'm-0 py-1 rounded-l-sm flex gap-2 items-center overflow-x-auto ' +
|
|
||||||
className
|
|
||||||
}
|
|
||||||
style={{ scrollbarWidth: 'thin' }}
|
style={{ scrollbarWidth: 'thin' }}
|
||||||
>
|
>
|
||||||
{state.nextEvents.includes('Enter sketch') && (
|
{state.nextEvents.includes('Enter sketch') && (
|
||||||
@ -73,7 +69,7 @@ export const Toolbar = () => {
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
send({ type: 'Enter sketch', data: { forceNewSketch: true } })
|
send({ type: 'Enter sketch', data: { forceNewSketch: true } })
|
||||||
}
|
}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'sketch',
|
icon: 'sketch',
|
||||||
iconClassName,
|
iconClassName,
|
||||||
bgClassName,
|
bgClassName,
|
||||||
@ -90,7 +86,7 @@ export const Toolbar = () => {
|
|||||||
className={buttonClassName}
|
className={buttonClassName}
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => send({ type: 'Enter sketch' })}
|
onClick={() => send({ type: 'Enter sketch' })}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'sketch',
|
icon: 'sketch',
|
||||||
iconClassName,
|
iconClassName,
|
||||||
bgClassName,
|
bgClassName,
|
||||||
@ -107,7 +103,7 @@ export const Toolbar = () => {
|
|||||||
className={buttonClassName}
|
className={buttonClassName}
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => send({ type: 'Cancel' })}
|
onClick={() => send({ type: 'Cancel' })}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'arrowLeft',
|
icon: 'arrowLeft',
|
||||||
iconClassName,
|
iconClassName,
|
||||||
bgClassName,
|
bgClassName,
|
||||||
@ -130,7 +126,7 @@ export const Toolbar = () => {
|
|||||||
: send('Equip Line tool')
|
: send('Equip Line tool')
|
||||||
}
|
}
|
||||||
aria-pressed={state?.matches('Sketch.Line tool')}
|
aria-pressed={state?.matches('Sketch.Line tool')}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'line',
|
icon: 'line',
|
||||||
iconClassName,
|
iconClassName,
|
||||||
bgClassName,
|
bgClassName,
|
||||||
@ -150,7 +146,7 @@ export const Toolbar = () => {
|
|||||||
: send('Equip tangential arc to')
|
: send('Equip tangential arc to')
|
||||||
}
|
}
|
||||||
aria-pressed={state.matches('Sketch.Tangential arc to')}
|
aria-pressed={state.matches('Sketch.Tangential arc to')}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'arc',
|
icon: 'arc',
|
||||||
iconClassName,
|
iconClassName,
|
||||||
bgClassName,
|
bgClassName,
|
||||||
@ -174,7 +170,7 @@ export const Toolbar = () => {
|
|||||||
: send('Equip rectangle tool')
|
: send('Equip rectangle tool')
|
||||||
}
|
}
|
||||||
aria-pressed={state.matches('Sketch.Rectangle tool')}
|
aria-pressed={state.matches('Sketch.Rectangle tool')}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'rectangle',
|
icon: 'rectangle',
|
||||||
iconClassName,
|
iconClassName,
|
||||||
bgClassName,
|
bgClassName,
|
||||||
@ -196,52 +192,54 @@ export const Toolbar = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{state.matches('Sketch.SketchIdle') &&
|
{state.matches('Sketch.SketchIdle') &&
|
||||||
state.nextEvents
|
state.nextEvents.filter(
|
||||||
.filter(
|
(eventName) =>
|
||||||
(eventName) =>
|
eventName.includes('Make segment') ||
|
||||||
eventName.includes('Make segment') ||
|
eventName.includes('Constrain')
|
||||||
eventName.includes('Constrain')
|
).length > 0 && (
|
||||||
)
|
<ActionButtonDropdown
|
||||||
.sort((a, b) => {
|
splitMenuItems={state.nextEvents
|
||||||
const aisEnabled = state.nextEvents
|
.filter(
|
||||||
.filter((event) => state.can(event as any))
|
(eventName) =>
|
||||||
.includes(a)
|
eventName.includes('Make segment') ||
|
||||||
const bIsEnabled = state.nextEvents
|
eventName.includes('Constrain')
|
||||||
.filter((event) => state.can(event as any))
|
)
|
||||||
.includes(b)
|
.sort((a, b) => {
|
||||||
if (aisEnabled && !bIsEnabled) {
|
const aisEnabled = state.nextEvents
|
||||||
return -1
|
.filter((event) => state.can(event as any))
|
||||||
}
|
.includes(a)
|
||||||
if (!aisEnabled && bIsEnabled) {
|
const bIsEnabled = state.nextEvents
|
||||||
return 1
|
.filter((event) => state.can(event as any))
|
||||||
}
|
.includes(b)
|
||||||
return 0
|
if (aisEnabled && !bIsEnabled) {
|
||||||
})
|
return -1
|
||||||
.map((eventName) => (
|
}
|
||||||
<li className="contents" key={eventName}>
|
if (!aisEnabled && bIsEnabled) {
|
||||||
<ActionButton
|
return 1
|
||||||
className={buttonClassName}
|
}
|
||||||
Element="button"
|
return 0
|
||||||
key={eventName}
|
})
|
||||||
onClick={() => send(eventName)}
|
.map((eventName) => ({
|
||||||
disabled={
|
label: eventName
|
||||||
|
.replace('Make segment ', '')
|
||||||
|
.replace('Constrain ', ''),
|
||||||
|
onClick: () => send(eventName),
|
||||||
|
disabled:
|
||||||
!state.nextEvents
|
!state.nextEvents
|
||||||
.filter((event) => state.can(event as any))
|
.filter((event) => state.can(event as any))
|
||||||
.includes(eventName) || disableAllButtons
|
.includes(eventName) || disableAllButtons,
|
||||||
}
|
}))}
|
||||||
title={eventName}
|
className={buttonClassName}
|
||||||
icon={{
|
Element="button"
|
||||||
icon: 'line',
|
iconStart={{
|
||||||
iconClassName,
|
icon: 'dimension',
|
||||||
bgClassName,
|
iconClassName,
|
||||||
}}
|
bgClassName,
|
||||||
>
|
}}
|
||||||
{eventName
|
>
|
||||||
.replace('Make segment ', '')
|
Constrain
|
||||||
.replace('Constrain ', '')}
|
</ActionButtonDropdown>
|
||||||
</ActionButton>
|
)}
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
{state.matches('idle') && (
|
{state.matches('idle') && (
|
||||||
<li className="contents">
|
<li className="contents">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
@ -259,7 +257,7 @@ export const Toolbar = () => {
|
|||||||
? 'extrude'
|
? 'extrude'
|
||||||
: 'sketches need to be closed, or not already extruded'
|
: 'sketches need to be closed, or not already extruded'
|
||||||
}
|
}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'extrude',
|
icon: 'extrude',
|
||||||
iconClassName,
|
iconClassName,
|
||||||
bgClassName,
|
bgClassName,
|
||||||
@ -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 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
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { ActionIcon, ActionIconProps } from './ActionIcon'
|
import { ActionIcon, ActionIconProps } from './ActionIcon'
|
||||||
import React from 'react'
|
import React, { ForwardedRef, forwardRef } from 'react'
|
||||||
import { paths } from 'lib/paths'
|
import { paths } from 'lib/paths'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import type { LinkProps } from 'react-router-dom'
|
import type { LinkProps } from 'react-router-dom'
|
||||||
|
|
||||||
interface BaseActionButtonProps {
|
interface BaseActionButtonProps {
|
||||||
icon?: ActionIconProps
|
iconStart?: ActionIconProps
|
||||||
|
iconEnd?: ActionIconProps
|
||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,15 +33,15 @@ type ActionButtonAsElement = BaseActionButtonProps &
|
|||||||
Element: React.ComponentType<React.HTMLAttributes<HTMLButtonElement>>
|
Element: React.ComponentType<React.HTMLAttributes<HTMLButtonElement>>
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActionButtonProps =
|
export type ActionButtonProps =
|
||||||
| ActionButtonAsButton
|
| ActionButtonAsButton
|
||||||
| ActionButtonAsLink
|
| ActionButtonAsLink
|
||||||
| ActionButtonAsExternal
|
| ActionButtonAsExternal
|
||||||
| ActionButtonAsElement
|
| ActionButtonAsElement
|
||||||
|
|
||||||
export const ActionButton = (props: ActionButtonProps) => {
|
export const ActionButton = forwardRef((props: ActionButtonProps, ref) => {
|
||||||
const classNames = `action-button m-0 group mono text-sm flex items-center gap-2 rounded-sm border-solid border border-chalkboard-30 hover:border-chalkboard-40 dark:border-chalkboard-70 dark:hover:border-chalkboard-60 dark:bg-chalkboard-90/50 p-[3px] text-chalkboard-100 dark:text-chalkboard-10 ${
|
const classNames = `action-button p-0 m-0 group mono text-xs leading-none flex items-center gap-2 rounded-sm border-solid border border-chalkboard-30 hover:border-chalkboard-40 enabled:dark:border-chalkboard-70 dark:hover:border-chalkboard-60 dark:bg-chalkboard-90/50 text-chalkboard-100 dark:text-chalkboard-10 ${
|
||||||
props.icon ? 'pr-2' : 'px-2'
|
props.iconStart ? (props.iconEnd ? 'px-0' : 'pr-2') : 'px-2'
|
||||||
} ${props.className ? props.className : ''}`
|
} ${props.className ? props.className : ''}`
|
||||||
|
|
||||||
switch (props.Element) {
|
switch (props.Element) {
|
||||||
@ -48,11 +49,23 @@ export const ActionButton = (props: ActionButtonProps) => {
|
|||||||
// Note we have to destructure 'className' and 'Element' out of props
|
// Note we have to destructure 'className' and 'Element' out of props
|
||||||
// because we don't want to pass them to the button element;
|
// because we don't want to pass them to the button element;
|
||||||
// the same is true for the other cases below.
|
// the same is true for the other cases below.
|
||||||
const { Element, icon, children, className: _className, ...rest } = props
|
const {
|
||||||
|
Element,
|
||||||
|
iconStart,
|
||||||
|
iconEnd,
|
||||||
|
children,
|
||||||
|
className: _className,
|
||||||
|
...rest
|
||||||
|
} = props
|
||||||
return (
|
return (
|
||||||
<button className={classNames} {...rest}>
|
<button
|
||||||
{props.icon && <ActionIcon {...icon} />}
|
ref={ref as ForwardedRef<HTMLButtonElement>}
|
||||||
|
className={classNames}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{iconStart && <ActionIcon {...iconStart} />}
|
||||||
{children}
|
{children}
|
||||||
|
{iconEnd && <ActionIcon {...iconEnd} />}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -60,15 +73,22 @@ export const ActionButton = (props: ActionButtonProps) => {
|
|||||||
const {
|
const {
|
||||||
Element,
|
Element,
|
||||||
to,
|
to,
|
||||||
icon,
|
iconStart,
|
||||||
|
iconEnd,
|
||||||
children,
|
children,
|
||||||
className: _className,
|
className: _className,
|
||||||
...rest
|
...rest
|
||||||
} = props
|
} = props
|
||||||
return (
|
return (
|
||||||
<Link to={to || paths.INDEX} className={classNames} {...rest}>
|
<Link
|
||||||
{icon && <ActionIcon {...icon} />}
|
ref={ref as ForwardedRef<HTMLAnchorElement>}
|
||||||
|
to={to || paths.INDEX}
|
||||||
|
className={classNames}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{iconStart && <ActionIcon {...iconStart} />}
|
||||||
{children}
|
{children}
|
||||||
|
{iconEnd && <ActionIcon {...iconEnd} />}
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -76,33 +96,42 @@ export const ActionButton = (props: ActionButtonProps) => {
|
|||||||
const {
|
const {
|
||||||
Element,
|
Element,
|
||||||
to,
|
to,
|
||||||
icon,
|
iconStart,
|
||||||
|
iconEnd,
|
||||||
children,
|
children,
|
||||||
className: _className,
|
className: _className,
|
||||||
...rest
|
...rest
|
||||||
} = props
|
} = props
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
|
ref={ref as ForwardedRef<HTMLAnchorElement>}
|
||||||
to={to || paths.INDEX}
|
to={to || paths.INDEX}
|
||||||
className={classNames}
|
className={classNames}
|
||||||
{...rest}
|
{...rest}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
{icon && <ActionIcon {...icon} />}
|
{iconStart && <ActionIcon {...iconStart} />}
|
||||||
{children}
|
{children}
|
||||||
|
{iconEnd && <ActionIcon {...iconEnd} />}
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
const { Element, icon, children, className: _className, ...rest } = props
|
const {
|
||||||
if (!Element) throw new Error('Element is required')
|
Element,
|
||||||
|
iconStart,
|
||||||
|
children,
|
||||||
|
className: _className,
|
||||||
|
...rest
|
||||||
|
} = props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Element className={classNames} {...rest}>
|
<Element className={classNames} {...rest}>
|
||||||
{props.icon && <ActionIcon {...props.icon} />}
|
{props.iconStart && <ActionIcon {...props.iconStart} />}
|
||||||
{children}
|
{children}
|
||||||
|
{props.iconEnd && <ActionIcon {...props.iconEnd} />}
|
||||||
</Element>
|
</Element>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
55
src/components/ActionButtonDropdown.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { Popover } from '@headlessui/react'
|
||||||
|
import { ActionButton, ActionButtonProps } from './ActionButton'
|
||||||
|
|
||||||
|
type ActionButtonSplitProps = Omit<ActionButtonProps, 'iconEnd'> & {
|
||||||
|
splitMenuItems: {
|
||||||
|
label: string
|
||||||
|
shortcut?: string
|
||||||
|
onClick: () => void
|
||||||
|
disabled?: boolean
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ActionButtonDropdown({
|
||||||
|
splitMenuItems,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: ActionButtonSplitProps) {
|
||||||
|
return (
|
||||||
|
<Popover className="relative">
|
||||||
|
<Popover.Button
|
||||||
|
as={ActionButton}
|
||||||
|
className={className}
|
||||||
|
{...props}
|
||||||
|
Element="button"
|
||||||
|
iconEnd={{
|
||||||
|
icon: 'caretDown',
|
||||||
|
className: 'ui-open:rotate-180',
|
||||||
|
bgClassName:
|
||||||
|
'bg-chalkboard-20 dark:bg-chalkboard-80 ui-open:bg-primary ui-open:text-chalkboard-10',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Popover.Panel
|
||||||
|
as="ul"
|
||||||
|
className="absolute z-20 left-1/2 -translate-x-1/2 top-full mt-1 w-fit max-h-[80vh] overflow-y-auto py-2 flex flex-col gap-1 align-stretch text-inherit dark:text-chalkboard-10 bg-chalkboard-10 dark:bg-chalkboard-100 rounded shadow-lg border border-solid border-chalkboard-30 dark:border-chalkboard-80 text-sm m-0 p-0"
|
||||||
|
>
|
||||||
|
{splitMenuItems.map((item) => (
|
||||||
|
<li className="contents" key={item.label}>
|
||||||
|
<button
|
||||||
|
onClick={item.onClick}
|
||||||
|
className="block px-3 py-1 hover:bg-primary/10 dark:hover:bg-chalkboard-80 border-0 m-0 text-sm w-full rounded-none text-left disabled:!bg-transparent dark:disabled:text-chalkboard-60"
|
||||||
|
disabled={item.disabled}
|
||||||
|
>
|
||||||
|
<span className="capitalize">{item.label}</span>
|
||||||
|
{item.shortcut && (
|
||||||
|
<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">
|
||||||
|
{item.shortcut}
|
||||||
|
</kbd>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</Popover.Panel>
|
||||||
|
</Popover>
|
||||||
|
)
|
||||||
|
}
|
@ -29,10 +29,8 @@ export const ActionIcon = ({
|
|||||||
size = 'md',
|
size = 'md',
|
||||||
children,
|
children,
|
||||||
}: ActionIconProps) => {
|
}: ActionIconProps) => {
|
||||||
// By default, we reverse the icon color and background color in dark mode
|
const computedIconClassName = `h-auto text-inherit dark:text-current !group-disabled:text-chalkboard-60 !group-disabled:text-chalkboard-60 ${iconClassName}`
|
||||||
const computedIconClassName = `h-auto text-primary dark:text-current !group-disabled:text-chalkboard-60 !group-disabled:text-chalkboard-60 ${iconClassName}`
|
const computedBgClassName = `bg-chalkboard-20 dark:bg-chalkboard-80 !group-disabled:bg-chalkboard-30 !dark:group-disabled:bg-chalkboard-80 ${bgClassName}`
|
||||||
|
|
||||||
const computedBgClassName = `bg-primary/10 dark:bg-chalkboard-90 !group-disabled:bg-chalkboard-30 !dark:group-disabled:bg-chalkboard-80 ${bgClassName}`
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -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} />
|
||||||
</>
|
</>
|
||||||
|
@ -175,7 +175,7 @@ function ReviewingButton() {
|
|||||||
type="submit"
|
type="submit"
|
||||||
form="review-form"
|
form="review-form"
|
||||||
className="w-fit !p-0 rounded-sm border !border-primary hover:shadow"
|
className="w-fit !p-0 rounded-sm border !border-primary hover:shadow"
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'checkmark',
|
icon: 'checkmark',
|
||||||
bgClassName: 'p-1 rounded-sm !bg-primary hover:brightness-110',
|
bgClassName: 'p-1 rounded-sm !bg-primary hover:brightness-110',
|
||||||
iconClassName: '!text-chalkboard-10',
|
iconClassName: '!text-chalkboard-10',
|
||||||
@ -193,7 +193,7 @@ function GatheringArgsButton() {
|
|||||||
type="submit"
|
type="submit"
|
||||||
form="arg-form"
|
form="arg-form"
|
||||||
className="w-fit !p-0 rounded-sm border !border-primary hover:shadow"
|
className="w-fit !p-0 rounded-sm border !border-primary hover:shadow"
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'arrowRight',
|
icon: 'arrowRight',
|
||||||
bgClassName: 'p-1 rounded-sm !bg-primary hover:brightness-110',
|
bgClassName: 'p-1 rounded-sm !bg-primary hover:brightness-110',
|
||||||
iconClassName: '!text-chalkboard-10',
|
iconClassName: '!text-chalkboard-10',
|
||||||
|
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)}
|
||||||
|
@ -71,6 +71,16 @@ const CustomIconMap = {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
|
caretDown: (
|
||||||
|
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M10 11.2929L6.35346 7.64642L5.64636 8.35354L9.64648 12.3536L10.3536 12.3536L14.3535 8.35353L13.6464 7.64643L10 11.2929Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
),
|
||||||
clipboardCheckmark: (
|
clipboardCheckmark: (
|
||||||
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path
|
<path
|
||||||
@ -101,6 +111,16 @@ const CustomIconMap = {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
|
dimension: (
|
||||||
|
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M15.6455 3.6455L14 2V5.291L5.291 14H2L6 18V14.7052L14.7052 6H18L16.3526 4.35261L16.3546 4.35065L15.6475 3.64354L15.6455 3.6455Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
),
|
||||||
equal: (
|
equal: (
|
||||||
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path
|
<path
|
||||||
|
@ -25,7 +25,7 @@ const DownloadAppBanner = () => {
|
|||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => setIsBannerDismissed(true)}
|
onClick={() => setIsBannerDismissed(true)}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'close',
|
icon: 'close',
|
||||||
className: 'p-1',
|
className: 'p-1',
|
||||||
bgClassName:
|
bgClassName:
|
||||||
|
@ -29,7 +29,7 @@ export const ErrorPage = () => {
|
|||||||
<ActionButton
|
<ActionButton
|
||||||
Element="link"
|
Element="link"
|
||||||
to={'/'}
|
to={'/'}
|
||||||
icon={{ icon: faHome }}
|
iconStart={{ icon: faHome }}
|
||||||
data-testid="unexpected-error-home"
|
data-testid="unexpected-error-home"
|
||||||
>
|
>
|
||||||
Go Home
|
Go Home
|
||||||
@ -37,14 +37,14 @@ export const ErrorPage = () => {
|
|||||||
)}
|
)}
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
icon={{ icon: faRefresh }}
|
iconStart={{ icon: faRefresh }}
|
||||||
onClick={() => window.location.reload()}
|
onClick={() => window.location.reload()}
|
||||||
>
|
>
|
||||||
Reload
|
Reload
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
icon={{ icon: faTrash }}
|
iconStart={{ icon: faTrash }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
window.localStorage.clear()
|
window.localStorage.clear()
|
||||||
}}
|
}}
|
||||||
@ -53,7 +53,7 @@ export const ErrorPage = () => {
|
|||||||
</ActionButton>
|
</ActionButton>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="externalLink"
|
Element="externalLink"
|
||||||
icon={{ icon: faBug }}
|
iconStart={{ icon: faBug }}
|
||||||
to="https://github.com/KittyCAD/modeling-app/issues/new"
|
to="https://github.com/KittyCAD/modeling-app/issues/new"
|
||||||
>
|
>
|
||||||
Report Bug
|
Report Bug
|
||||||
|
@ -109,7 +109,7 @@ function DeleteConfirmationDialog({
|
|||||||
send({ type: 'Delete file', data: fileOrDir })
|
send({ type: 'Delete file', data: fileOrDir })
|
||||||
setIsOpen(false)
|
setIsOpen(false)
|
||||||
}}
|
}}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: faTrashAlt,
|
icon: faTrashAlt,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
iconClassName:
|
iconClassName:
|
||||||
@ -340,7 +340,7 @@ export const FileTreeMenu = () => {
|
|||||||
<>
|
<>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'filePlus',
|
icon: 'filePlus',
|
||||||
iconClassName: '!text-current',
|
iconClassName: '!text-current',
|
||||||
bgClassName: 'bg-transparent',
|
bgClassName: 'bg-transparent',
|
||||||
@ -355,7 +355,7 @@ export const FileTreeMenu = () => {
|
|||||||
|
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'folderPlus',
|
icon: 'folderPlus',
|
||||||
iconClassName: '!text-current',
|
iconClassName: '!text-current',
|
||||||
bgClassName: 'bg-transparent',
|
bgClassName: 'bg-transparent',
|
||||||
|
@ -85,7 +85,7 @@ function ProjectCard({
|
|||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
type="submit"
|
type="submit"
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: faCheck,
|
icon: faCheck,
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
className: 'p-1',
|
className: 'p-1',
|
||||||
@ -99,7 +99,7 @@ function ProjectCard({
|
|||||||
</ActionButton>
|
</ActionButton>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: faX,
|
icon: faX,
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
iconClassName: 'dark:!text-chalkboard-20',
|
iconClassName: 'dark:!text-chalkboard-20',
|
||||||
@ -141,7 +141,7 @@ function ProjectCard({
|
|||||||
<div className="absolute z-10 bottom-2 right-2 flex gap-1 items-center opacity-0 group-hover:opacity-100 group-focus-within:opacity-100">
|
<div className="absolute z-10 bottom-2 right-2 flex gap-1 items-center opacity-0 group-hover:opacity-100 group-focus-within:opacity-100">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: faPenAlt,
|
icon: faPenAlt,
|
||||||
className: 'p-1',
|
className: 'p-1',
|
||||||
iconClassName: 'dark:!text-chalkboard-20',
|
iconClassName: 'dark:!text-chalkboard-20',
|
||||||
@ -161,7 +161,7 @@ function ProjectCard({
|
|||||||
</ActionButton>
|
</ActionButton>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: faTrashAlt,
|
icon: faTrashAlt,
|
||||||
className: 'p-1',
|
className: 'p-1',
|
||||||
size: 'xs',
|
size: 'xs',
|
||||||
@ -207,7 +207,7 @@ function ProjectCard({
|
|||||||
await handleDeleteProject(project)
|
await handleDeleteProject(project)
|
||||||
setIsConfirmingDelete(false)
|
setIsConfirmingDelete(false)
|
||||||
}}
|
}}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: faTrashAlt,
|
icon: faTrashAlt,
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
className: 'p-1',
|
className: 'p-1',
|
||||||
|
@ -165,7 +165,7 @@ function ProjectMenuPopover({
|
|||||||
<div className="flex flex-col gap-2 p-4 dark:bg-chalkboard-90">
|
<div className="flex flex-col gap-2 p-4 dark:bg-chalkboard-90">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
icon={{ icon: 'exportFile', className: 'p-1' }}
|
iconStart={{ icon: 'exportFile', className: 'p-1' }}
|
||||||
className="border-transparent dark:border-transparent"
|
className="border-transparent dark:border-transparent"
|
||||||
disabled={!findCommand(exportCommandInfo)}
|
disabled={!findCommand(exportCommandInfo)}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@ -185,7 +185,7 @@ function ProjectMenuPopover({
|
|||||||
// Clear the scene and end the session.
|
// Clear the scene and end the session.
|
||||||
engineCommandManager.endSession()
|
engineCommandManager.endSession()
|
||||||
}}
|
}}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'arrowLeft',
|
icon: 'arrowLeft',
|
||||||
className: 'p-1',
|
className: 'p-1',
|
||||||
}}
|
}}
|
||||||
|
@ -78,7 +78,7 @@ export const SetVarNameModal = ({
|
|||||||
Element="button"
|
Element="button"
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!isNewVariableNameUnique}
|
disabled={!isNewVariableNameUnique}
|
||||||
icon={{ icon: faPlus }}
|
iconStart={{ icon: faPlus }}
|
||||||
>
|
>
|
||||||
Add variable
|
Add variable
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
|
@ -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(),
|
||||||
|
@ -59,7 +59,7 @@ export const UpdaterModal = ({
|
|||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => onResolve({ wantUpdate: false })}
|
onClick={() => onResolve({ wantUpdate: false })}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'close',
|
icon: 'close',
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
iconClassName: 'text-destroy-20 group-hover:text-destroy-10',
|
iconClassName: 'text-destroy-20 group-hover:text-destroy-10',
|
||||||
@ -72,7 +72,10 @@ export const UpdaterModal = ({
|
|||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => onResolve({ wantUpdate: true })}
|
onClick={() => onResolve({ wantUpdate: true })}
|
||||||
icon={{ icon: 'arrowRight', bgClassName: 'dark:bg-chalkboard-80' }}
|
iconStart={{
|
||||||
|
icon: 'arrowRight',
|
||||||
|
bgClassName: 'dark:bg-chalkboard-80',
|
||||||
|
}}
|
||||||
className="dark:hover:bg-chalkboard-80/50"
|
className="dark:hover:bg-chalkboard-80/50"
|
||||||
data-testid="update-button-update"
|
data-testid="update-button-update"
|
||||||
>
|
>
|
||||||
|
@ -31,7 +31,7 @@ export const UpdaterRestartModal = ({
|
|||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => onResolve({ wantRestart: false })}
|
onClick={() => onResolve({ wantRestart: false })}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'close',
|
icon: 'close',
|
||||||
bgClassName: 'bg-destroy-80',
|
bgClassName: 'bg-destroy-80',
|
||||||
iconClassName: 'text-destroy-20 group-hover:text-destroy-10',
|
iconClassName: 'text-destroy-20 group-hover:text-destroy-10',
|
||||||
@ -44,7 +44,10 @@ export const UpdaterRestartModal = ({
|
|||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => onResolve({ wantRestart: true })}
|
onClick={() => onResolve({ wantRestart: true })}
|
||||||
icon={{ icon: 'arrowRight', bgClassName: 'dark:bg-chalkboard-80' }}
|
iconStart={{
|
||||||
|
icon: 'arrowRight',
|
||||||
|
bgClassName: 'dark:bg-chalkboard-80',
|
||||||
|
}}
|
||||||
className="dark:hover:bg-chalkboard-80/50"
|
className="dark:hover:bg-chalkboard-80/50"
|
||||||
data-testid="update-restrart-button-update"
|
data-testid="update-restrart-button-update"
|
||||||
>
|
>
|
||||||
|
@ -55,7 +55,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
|
|||||||
) : (
|
) : (
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element={Popover.Button}
|
Element={Popover.Button}
|
||||||
icon={{ icon: 'menu' }}
|
iconStart={{ icon: 'menu' }}
|
||||||
className="border-transparent !px-0"
|
className="border-transparent !px-0"
|
||||||
data-testid="user-sidebar-toggle"
|
data-testid="user-sidebar-toggle"
|
||||||
>
|
>
|
||||||
@ -120,7 +120,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
|
|||||||
<div className="p-4 flex flex-col gap-2">
|
<div className="p-4 flex flex-col gap-2">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
icon={{ icon: 'settings' }}
|
iconStart={{ icon: 'settings' }}
|
||||||
className="border-transparent dark:border-transparent hover:bg-transparent"
|
className="border-transparent dark:border-transparent hover:bg-transparent"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// since /settings is a nested route the sidebar doesn't close
|
// since /settings is a nested route the sidebar doesn't close
|
||||||
@ -138,7 +138,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
|
|||||||
<ActionButton
|
<ActionButton
|
||||||
Element="externalLink"
|
Element="externalLink"
|
||||||
to="https://github.com/KittyCAD/modeling-app/discussions"
|
to="https://github.com/KittyCAD/modeling-app/discussions"
|
||||||
icon={{ icon: faGithub, className: 'p-1', size: 'sm' }}
|
iconStart={{ icon: faGithub, className: 'p-1', size: 'sm' }}
|
||||||
className="border-transparent dark:border-transparent"
|
className="border-transparent dark:border-transparent"
|
||||||
>
|
>
|
||||||
Request a feature
|
Request a feature
|
||||||
@ -146,7 +146,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
|
|||||||
<ActionButton
|
<ActionButton
|
||||||
Element="externalLink"
|
Element="externalLink"
|
||||||
to="https://github.com/KittyCAD/modeling-app/issues/new/choose"
|
to="https://github.com/KittyCAD/modeling-app/issues/new/choose"
|
||||||
icon={{ icon: faBug, className: 'p-1', size: 'sm' }}
|
iconStart={{ icon: faBug, className: 'p-1', size: 'sm' }}
|
||||||
className="border-transparent dark:border-transparent"
|
className="border-transparent dark:border-transparent"
|
||||||
>
|
>
|
||||||
Report a bug
|
Report a bug
|
||||||
@ -154,7 +154,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
|
|||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => send('Log out')}
|
onClick={() => send('Log out')}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: faSignOutAlt,
|
icon: faSignOutAlt,
|
||||||
className: 'p-1',
|
className: 'p-1',
|
||||||
bgClassName: '!bg-transparent',
|
bgClassName: '!bg-transparent',
|
||||||
|
@ -24,7 +24,7 @@ export function WasmErrBanner() {
|
|||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => setBannerDismissed(true)}
|
onClick={() => setBannerDismissed(true)}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: 'close',
|
icon: 'close',
|
||||||
className: 'p-1',
|
className: 'p-1',
|
||||||
bgClassName:
|
bgClassName:
|
||||||
|
@ -264,8 +264,12 @@ export class LanguageServerPlugin implements PluginValue {
|
|||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
this.sendChange({
|
this.client.textDocumentDidChange({
|
||||||
documentText: this.view.state.doc.toString(),
|
textDocument: {
|
||||||
|
uri: this.documentUri,
|
||||||
|
version: this.documentVersion++,
|
||||||
|
},
|
||||||
|
contentChanges: [{ text: this.view.state.doc.toString() }],
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = await this.client.textDocumentFormatting({
|
const result = await this.client.textDocumentFormatting({
|
||||||
|
@ -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 ||
|
||||||
|
@ -79,6 +79,7 @@ export default class CodeManager {
|
|||||||
if (this._code !== code) {
|
if (this._code !== code) {
|
||||||
this.code = code
|
this.code = code
|
||||||
this.#updateState(code)
|
this.#updateState(code)
|
||||||
|
this.updateCodeEditor(code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -210,7 +210,7 @@ const Home = () => {
|
|||||||
: '')
|
: '')
|
||||||
}
|
}
|
||||||
onClick={() => setSearchParams(getNextSearchParams(sort, 'name'))}
|
onClick={() => setSearchParams(getNextSearchParams(sort, 'name'))}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: getSortIcon(sort, 'name'),
|
icon: getSortIcon(sort, 'name'),
|
||||||
className: 'p-1.5',
|
className: 'p-1.5',
|
||||||
iconClassName: !sort.includes('name')
|
iconClassName: !sort.includes('name')
|
||||||
@ -232,7 +232,7 @@ const Home = () => {
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
setSearchParams(getNextSearchParams(sort, 'modified'))
|
setSearchParams(getNextSearchParams(sort, 'modified'))
|
||||||
}
|
}
|
||||||
icon={{
|
iconStart={{
|
||||||
icon: sort ? getSortIcon(sort, 'modified') : faArrowDown,
|
icon: sort ? getSortIcon(sort, 'modified') : faArrowDown,
|
||||||
className: 'p-1.5',
|
className: 'p-1.5',
|
||||||
iconClassName: !isSortByModified ? '!text-chalkboard-40' : '',
|
iconClassName: !isSortByModified ? '!text-chalkboard-40' : '',
|
||||||
@ -278,7 +278,7 @@ const Home = () => {
|
|||||||
<ActionButton
|
<ActionButton
|
||||||
Element="button"
|
Element="button"
|
||||||
onClick={() => send('Create project')}
|
onClick={() => send('Create project')}
|
||||||
icon={{ icon: faPlus, iconClassName: 'p-1 w-4' }}
|
iconStart={{ icon: faPlus, iconClassName: 'p-1 w-4' }}
|
||||||
data-testid="home-new-file"
|
data-testid="home-new-file"
|
||||||
>
|
>
|
||||||
New project
|
New project
|
||||||
|
@ -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,21 +11,13 @@ 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-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
(buttonDownInStream ? '' : ' pointer-events-auto')
|
(buttonDownInStream ? '' : ' pointer-events-auto')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1">
|
<section className="flex-1 overflow-y-auto">
|
||||||
<h2 className="text-3xl font-bold">
|
<h2 className="text-3xl font-bold">
|
||||||
Editing code with <span className="text-primary">kcl</span>
|
Editing code with <span className="text-primary">kcl</span>
|
||||||
</h2>
|
</h2>
|
||||||
|
@ -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,17 +12,9 @@ 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-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
(buttonDownInStream ? '' : ' pointer-events-auto')
|
(buttonDownInStream ? '' : ' pointer-events-auto')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -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,17 +28,9 @@ 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-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
(buttonDownInStream ? '' : ' pointer-events-auto')
|
(buttonDownInStream ? '' : ' pointer-events-auto')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -13,11 +13,11 @@ export default function Streaming() {
|
|||||||
<div className="fixed grid justify-start items-center inset-0 z-50 pointer-events-none">
|
<div className="fixed grid justify-start items-center inset-0 z-50 pointer-events-none">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'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' +
|
'max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
(buttonDownInStream ? '' : ' pointer-events-auto')
|
(buttonDownInStream ? '' : ' pointer-events-auto')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1">
|
<section className="flex-1 overflow-y-auto">
|
||||||
<h2 className="text-3xl font-bold">Streaming Video</h2>
|
<h2 className="text-3xl font-bold">Streaming Video</h2>
|
||||||
<p className="my-4">
|
<p className="my-4">
|
||||||
Historically, CAD programs run on your computer, so to run
|
Historically, CAD programs run on your computer, so to run
|
||||||
|