Compare commits
48 Commits
Author | SHA1 | Date | |
---|---|---|---|
7ac6a3a4f2 | |||
3cbf2b194a | |||
44f06aa199 | |||
1b878865b8 | |||
3b840e9a80 | |||
4a0811eec8 | |||
e63bf5db11 | |||
863e4e206f | |||
f1cd2355c6 | |||
164b675a86 | |||
b1afe1c541 | |||
26ef7218b2 | |||
e5a4fb439c | |||
97ad66a358 | |||
26438270ff | |||
a0cfda6d7a | |||
58a62b8097 | |||
e2909c509f | |||
07eaf93e78 | |||
6a5ca3088a | |||
6501072d80 | |||
726fd02bad | |||
d0f9ae475f | |||
da323e22d4 | |||
8dc3628e9b | |||
253744867b | |||
c45eb1e3e3 | |||
758aac9328 | |||
309943cf2c | |||
b3d4ab91fc | |||
5e73fa45f0 | |||
17d23a17db | |||
0460f8eaee | |||
2077cdb6fc | |||
cb0b7e8169 | |||
3a05211d30 | |||
d12d103cba | |||
04f6d3dcc8 | |||
9c9ffa0d03 | |||
c62b9f1f04 | |||
fcac3c72e4 | |||
1e2f577a9f | |||
1814f340fb | |||
43928f88aa | |||
6959036688 | |||
570d0473c6 | |||
44f0d7c25c | |||
3ccb04c4e7 |
16
.github/workflows/ci.yml
vendored
@ -239,8 +239,8 @@ jobs:
|
||||
includeDebug: true
|
||||
args: "${{ env.TAURI_ARGS_MACOS }} ${{ env.TAURI_ARGS_UBUNTU }}"
|
||||
|
||||
- name: Mac App Store
|
||||
if: ${{ env.BUILD_RELEASE == 'true' && matrix.os == 'macos-14' }}
|
||||
- name: Build for Mac TestFlight (nightly)
|
||||
if: ${{ github.event_name == 'schedule' && matrix.os == 'macos-14' }}
|
||||
shell: bash
|
||||
run: |
|
||||
unset APPLE_SIGNING_IDENTITY
|
||||
@ -302,9 +302,9 @@ jobs:
|
||||
APPLE_STORE_P12_PASSWORD: ${{ secrets.APPLE_STORE_P12_PASSWORD }}
|
||||
|
||||
|
||||
- name: 'Upload app to TestFlight'
|
||||
- name: 'Upload to Mac TestFlight (nightly)'
|
||||
uses: apple-actions/upload-testflight-build@v1
|
||||
if: ${{ env.BUILD_RELEASE == 'true' && matrix.os == 'macos-14' }}
|
||||
if: ${{ github.event_name == 'schedule' && matrix.os == 'macos-14' }}
|
||||
with:
|
||||
app-path: 'src-tauri/target/universal-apple-darwin/release/bundle/macos/Zoo Modeling App.pkg'
|
||||
issuer-id: ${{ secrets.APPLE_STORE_ISSUER_ID }}
|
||||
@ -313,8 +313,8 @@ jobs:
|
||||
app-type: osx
|
||||
|
||||
|
||||
- name: Clean up after Mac App Store
|
||||
if: ${{ env.BUILD_RELEASE == 'true' && matrix.os == 'macos-14' }}
|
||||
- name: Clean up after Mac TestFlight (nightly)
|
||||
if: ${{ github.event_name == 'schedule' && matrix.os == 'macos-14' }}
|
||||
shell: bash
|
||||
run: |
|
||||
git status
|
||||
@ -354,7 +354,7 @@ jobs:
|
||||
path: "${{ env.PREFIX }}/${{ env.MODE }}/bundle/*/*"
|
||||
|
||||
- name: Run e2e tests (linux only)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
if: ${{ matrix.os == 'ubuntu-latest' && github.event_name != 'release' && github.event_name != 'schedule' }}
|
||||
run: |
|
||||
cargo install tauri-driver --force
|
||||
source .env.${{ env.BUILD_RELEASE == 'true' && 'production' || 'development' }}
|
||||
@ -440,7 +440,7 @@ jobs:
|
||||
cat last_download.json
|
||||
|
||||
- name: Authenticate to Google Cloud
|
||||
uses: 'google-github-actions/auth@v2.1.2'
|
||||
uses: 'google-github-actions/auth@v2.1.3'
|
||||
with:
|
||||
credentials_json: '${{ secrets.GOOGLE_CLOUD_DL_SA }}'
|
||||
|
||||
|
4
.github/workflows/create-release.yml
vendored
@ -17,11 +17,11 @@ jobs:
|
||||
name: Read Cut release PR info and create release
|
||||
with:
|
||||
script: |
|
||||
const { owner, repo, sha } = context.repo
|
||||
const { owner, repo } = context.repo
|
||||
const pulls = await github.rest.repos.listPullRequestsAssociatedWithCommit({
|
||||
owner,
|
||||
repo,
|
||||
commit_sha: sha,
|
||||
commit_sha: context.sha,
|
||||
})
|
||||
const { title, body } = pulls.data[0]
|
||||
const version = title.split('Cut release ')[1]
|
||||
|
@ -31,7 +31,6 @@ layout: manual
|
||||
* [`fillet`](kcl/fillet)
|
||||
* [`floor`](kcl/floor)
|
||||
* [`getEdge`](kcl/getEdge)
|
||||
* [`getExtrudeWallTransform`](kcl/getExtrudeWallTransform)
|
||||
* [`getNextAdjacentEdge`](kcl/getNextAdjacentEdge)
|
||||
* [`getOppositeEdge`](kcl/getOppositeEdge)
|
||||
* [`getPreviousAdjacentEdge`](kcl/getPreviousAdjacentEdge)
|
||||
|
@ -12,6 +12,8 @@ import {
|
||||
TEST_SETTINGS_ONBOARDING_START,
|
||||
} from './storageStates'
|
||||
import * as TOML from '@iarna/toml'
|
||||
import { Coords2d } from 'lang/std/sketch'
|
||||
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
|
||||
|
||||
/*
|
||||
debug helper: unfortunately we do rely on exact coord mouse clicks in a few places
|
||||
@ -130,6 +132,7 @@ test('Basic sketch', async ({ page }) => {
|
||||
// selected two lines therefore there should be two cursors
|
||||
await expect(page.locator('.cm-cursor')).toHaveCount(2)
|
||||
|
||||
await page.getByRole('button', { name: 'Constrain' }).click()
|
||||
await page.getByRole('button', { name: 'Equal Length' }).click()
|
||||
|
||||
await expect(page.locator('.cm-content'))
|
||||
@ -263,6 +266,88 @@ test('Can moving camera', async ({ page, context }) => {
|
||||
}, [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 }) => {
|
||||
const u = getUtils(page)
|
||||
await page.setViewportSize({ width: 1000, height: 500 })
|
||||
@ -857,11 +942,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
|
||||
await topHorzSegmentClick()
|
||||
await page.keyboard.down('Shift')
|
||||
const constrainButton = page.getByRole('button', { name: 'Constrain' })
|
||||
const absYButton = page.getByRole('button', { name: 'ABS Y' })
|
||||
await constrainButton.click()
|
||||
await expect(absYButton).toBeDisabled()
|
||||
await page.waitForTimeout(100)
|
||||
await xAxisClick()
|
||||
await page.keyboard.up('Shift')
|
||||
await constrainButton.click()
|
||||
await absYButton.and(page.locator(':not([disabled])')).waitFor()
|
||||
await expect(absYButton).not.toBeDisabled()
|
||||
|
||||
@ -871,12 +959,14 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
|
||||
await page.waitForTimeout(100)
|
||||
// same selection but click the axis first
|
||||
await xAxisClick()
|
||||
await constrainButton.click()
|
||||
await expect(absYButton).toBeDisabled()
|
||||
await page.keyboard.down('Shift')
|
||||
await page.waitForTimeout(100)
|
||||
await topHorzSegmentClick()
|
||||
|
||||
await page.keyboard.up('Shift')
|
||||
await constrainButton.click()
|
||||
await expect(absYButton).not.toBeDisabled()
|
||||
|
||||
// clear selection by clicking on nothing
|
||||
@ -885,10 +975,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
|
||||
await page.getByText(` |> line([-${commonPoints.num2}, 0], %)`).click()
|
||||
await page.keyboard.down('Shift')
|
||||
await constrainButton.click()
|
||||
await expect(absYButton).toBeDisabled()
|
||||
await page.waitForTimeout(100)
|
||||
await xAxisClick()
|
||||
await page.keyboard.up('Shift')
|
||||
await constrainButton.click()
|
||||
await expect(absYButton).not.toBeDisabled()
|
||||
|
||||
// clear selection by clicking on nothing
|
||||
@ -950,9 +1042,8 @@ test.describe('Command bar tests', () => {
|
||||
let cmdSearchBar = page.getByPlaceholder('Search commands')
|
||||
|
||||
// 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
|
||||
.getByRole('button', { name: 'Ctrl+/' })
|
||||
.getByRole('button', { name: 'Commands', exact: false })
|
||||
.or(page.getByRole('button', { name: '⌘K' }))
|
||||
.click()
|
||||
await expect(cmdSearchBar).toBeVisible()
|
||||
@ -997,13 +1088,13 @@ test.describe('Command bar tests', () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
`const distance = sqrt(20)
|
||||
const part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([-6.95, 4.98], %)
|
||||
|> line([25.1, 0.41], %)
|
||||
|> line([0.73, -14.93], %)
|
||||
|> line([-23.44, 0.52], %)
|
||||
|> close(%)
|
||||
`
|
||||
const part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([-6.95, 10.98], %)
|
||||
|> line([25.1, 0.41], %)
|
||||
|> line([0.73, -20.93], %)
|
||||
|> line([-23.44, 0.52], %)
|
||||
|> close(%)
|
||||
`
|
||||
)
|
||||
})
|
||||
|
||||
@ -1020,7 +1111,6 @@ test.describe('Command bar tests', () => {
|
||||
page.getByRole('button', { name: 'Start Sketch' })
|
||||
).not.toBeDisabled()
|
||||
await u.clearCommandLogs()
|
||||
await page.getByText('|> line([0.73, -14.93], %)').click()
|
||||
await page.getByRole('button', { name: 'Extrude' }).isEnabled()
|
||||
|
||||
let cmdSearchBar = page.getByPlaceholder('Search commands')
|
||||
@ -1030,6 +1120,12 @@ test.describe('Command bar tests', () => {
|
||||
// Search for extrude command and choose it
|
||||
await page.getByRole('option', { name: 'Extrude' }).click()
|
||||
|
||||
// Assert that we're on the selection step
|
||||
await expect(page.getByRole('button', { name: 'selection' })).toBeDisabled()
|
||||
// Select a face
|
||||
await page.mouse.move(700, 200)
|
||||
await page.mouse.click(700, 200)
|
||||
|
||||
// Assert that we're on the distance step
|
||||
await expect(page.getByRole('button', { name: 'distance' })).toBeDisabled()
|
||||
|
||||
@ -1050,7 +1146,7 @@ test.describe('Command bar tests', () => {
|
||||
|
||||
// Assert we're back on the distance step
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Distance 12', exact: false })
|
||||
page.getByRole('button', { name: 'Distance 5', exact: false })
|
||||
).toBeDisabled()
|
||||
|
||||
await continueButton.click()
|
||||
@ -1061,11 +1157,11 @@ test.describe('Command bar tests', () => {
|
||||
// Unfortunately this indentation seems to matter for the test
|
||||
await expect(page.locator('.cm-content')).toHaveText(
|
||||
`const distance = sqrt(20)
|
||||
const distance001 = 5 + 7
|
||||
const distance001 = ${KCL_DEFAULT_LENGTH}
|
||||
const part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([-6.95, 4.98], %)
|
||||
|> startProfileAt([-6.95, 10.98], %)
|
||||
|> line([25.1, 0.41], %)
|
||||
|> line([0.73, -14.93], %)
|
||||
|> line([0.73, -20.93], %)
|
||||
|> line([-23.44, 0.52], %)
|
||||
|> close(%)
|
||||
|> extrude(distance001, %)`.replace(/(\r\n|\n|\r)/gm, '') // remove newlines
|
||||
@ -1256,6 +1352,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 (KCL_DEFAULT_LENGTH) => {
|
||||
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, %)
|
||||
`
|
||||
)
|
||||
}, KCL_DEFAULT_LENGTH)
|
||||
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 ({
|
||||
page,
|
||||
}) => {
|
||||
@ -1390,7 +1552,7 @@ test('Deselecting line tool should mean nothing happens on click', async ({
|
||||
`const part001 = startSketchOn('-XZ')`
|
||||
)
|
||||
|
||||
await page.waitForTimeout(300)
|
||||
await page.waitForTimeout(600)
|
||||
|
||||
let previousCodeContent = await page.locator('.cm-content').innerText()
|
||||
|
||||
@ -1752,6 +1914,7 @@ test('Can code mod a line length', async ({ page }) => {
|
||||
const startXPx = 500
|
||||
await page.mouse.move(startXPx + PUR * 15, 250 - PUR * 10)
|
||||
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.getByText('Add constraining value').click()
|
||||
|
||||
@ -1795,6 +1958,6 @@ test('Extrude from command bar selects extrude line after', async ({
|
||||
await page.keyboard.press('Enter')
|
||||
await page.waitForTimeout(100)
|
||||
await expect(page.locator('.cm-activeLine')).toHaveText(
|
||||
` |> extrude(5 + 7, %)`
|
||||
` |> extrude(${KCL_DEFAULT_LENGTH}, %)`
|
||||
)
|
||||
})
|
||||
|
@ -4,7 +4,7 @@ import { getUtils } from './test-utils'
|
||||
import { Models } from '@kittycad/lib'
|
||||
import fsp from 'fs/promises'
|
||||
import { spawn } from 'child_process'
|
||||
import { APP_NAME } from 'lib/constants'
|
||||
import { APP_NAME, KCL_DEFAULT_LENGTH } from 'lib/constants'
|
||||
import JSZip from 'jszip'
|
||||
import path from 'path'
|
||||
import { TEST_SETTINGS, TEST_SETTINGS_KEY } from './storageStates'
|
||||
@ -507,7 +507,7 @@ test('Draft rectangles should look right', async ({ page, context }) => {
|
||||
`const part001 = startSketchOn('-XZ')`
|
||||
)
|
||||
|
||||
await page.waitForTimeout(300) // TODO detect animation ending, or disable animation
|
||||
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
|
||||
await u.closeDebugPanel()
|
||||
|
||||
const startXPx = 600
|
||||
@ -597,12 +597,15 @@ test.describe('Client side scene scale should match engine scale', () => {
|
||||
|
||||
// exit sketch
|
||||
await u.openAndClearDebugPanel()
|
||||
await page.getByRole('button', { name: 'Exit Sketch' }).click()
|
||||
await u.doAndWaitForImageDiff(
|
||||
() => page.getByRole('button', { name: 'Exit Sketch' }).click(),
|
||||
200
|
||||
)
|
||||
|
||||
// wait for execution done
|
||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||
await u.clearAndCloseDebugPanel()
|
||||
await page.waitForTimeout(200)
|
||||
await page.waitForTimeout(300)
|
||||
|
||||
// second screen shot should look almost identical, i.e. scale should be the same.
|
||||
await expect(page).toHaveScreenshot({
|
||||
@ -696,12 +699,15 @@ test.describe('Client side scene scale should match engine scale', () => {
|
||||
|
||||
// exit sketch
|
||||
await u.openAndClearDebugPanel()
|
||||
await page.getByRole('button', { name: 'Exit Sketch' }).click()
|
||||
await u.doAndWaitForImageDiff(
|
||||
() => page.getByRole('button', { name: 'Exit Sketch' }).click(),
|
||||
200
|
||||
)
|
||||
|
||||
// wait for execution done
|
||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||
await u.clearAndCloseDebugPanel()
|
||||
await page.waitForTimeout(200)
|
||||
await page.waitForTimeout(300)
|
||||
|
||||
// second screen shot should look almost identical, i.e. scale should be the same.
|
||||
await expect(page).toHaveScreenshot({
|
||||
@ -712,7 +718,7 @@ test.describe('Client side scene scale should match engine scale', () => {
|
||||
|
||||
test('Sketch on face with none z-up', async ({ page, context }) => {
|
||||
const u = getUtils(page)
|
||||
await context.addInitScript(async () => {
|
||||
await context.addInitScript(async (KCL_DEFAULT_LENGTH) => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
`const part001 = startSketchOn('-XZ')
|
||||
@ -720,16 +726,16 @@ test('Sketch on face with none z-up', async ({ page, context }) => {
|
||||
|> line([9.31, 10.55], %, 'seg01')
|
||||
|> line([11.91, -10.42], %)
|
||||
|> close(%)
|
||||
|> extrude(5 + 7, %)
|
||||
|> extrude(${KCL_DEFAULT_LENGTH}, %)
|
||||
const part002 = startSketchOn(part001, 'seg01')
|
||||
|> startProfileAt([8, 8], %)
|
||||
|> line([4.68, 3.05], %)
|
||||
|> line([0, -7.79], %, 'seg02')
|
||||
|> close(%)
|
||||
|> extrude(5 + 7, %)
|
||||
|> extrude(${KCL_DEFAULT_LENGTH}, %)
|
||||
`
|
||||
)
|
||||
})
|
||||
}, KCL_DEFAULT_LENGTH)
|
||||
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
await page.goto('/')
|
||||
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 52 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: 32 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 47 KiB |
@ -15,7 +15,7 @@
|
||||
<script
|
||||
defer
|
||||
data-domain="app.zoo.dev"
|
||||
src="https://plausible.corp.zoo.dev/js/script.js"
|
||||
src="https://plausible.corp.zoo.dev/js/script.tagged-events.js"
|
||||
></script>
|
||||
<title>Zoo Modeling App</title>
|
||||
</head>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "untitled-app",
|
||||
"version": "0.20.0",
|
||||
"version": "0.21.4",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.16.0",
|
||||
@ -10,7 +10,7 @@
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@headlessui/react": "^1.7.19",
|
||||
"@headlessui/tailwindcss": "^0.2.0",
|
||||
"@kittycad/lib": "^0.0.58",
|
||||
"@kittycad/lib": "^0.0.60",
|
||||
"@lezer/javascript": "^1.4.9",
|
||||
"@open-rpc/client-js": "^1.8.1",
|
||||
"@react-hook/resize-observer": "^1.2.6",
|
||||
|
411
src-tauri/Cargo.lock
generated
@ -38,6 +38,17 @@ dependencies = [
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
|
||||
dependencies = [
|
||||
"getrandom 0.2.14",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
@ -81,6 +92,24 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_log-sys"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937"
|
||||
|
||||
[[package]]
|
||||
name = "android_logger"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c494134f746c14dc653a35a4ea5aca24ac368529da5370ecf41fe0341c35772f"
|
||||
dependencies = [
|
||||
"android_log-sys",
|
||||
"env_logger",
|
||||
"log",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
@ -140,9 +169,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.82"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
|
||||
checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
]
|
||||
@ -154,6 +183,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"kcl-lib",
|
||||
"kittycad",
|
||||
"log",
|
||||
"oauth2",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
@ -163,6 +193,7 @@ dependencies = [
|
||||
"tauri-plugin-dialog",
|
||||
"tauri-plugin-fs",
|
||||
"tauri-plugin-http",
|
||||
"tauri-plugin-log",
|
||||
"tauri-plugin-os",
|
||||
"tauri-plugin-process",
|
||||
"tauri-plugin-shell",
|
||||
@ -181,6 +212,12 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||
|
||||
[[package]]
|
||||
name = "ashpd"
|
||||
version = "0.8.1"
|
||||
@ -297,7 +334,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -332,7 +369,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -378,7 +415,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -507,6 +544,30 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "borsh"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbe5b10e214954177fb1dc9fbd20a1a2608fe99e6c832033bdc7cea287a20d77"
|
||||
dependencies = [
|
||||
"borsh-derive",
|
||||
"cfg_aliases 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "borsh-derive"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7a8646f94ab393e43e8b35a2558b1624bed28b97ee09c5d15456e3c9463f46d"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro-crate 3.1.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.63",
|
||||
"syn_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "3.5.0"
|
||||
@ -534,7 +595,7 @@ version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d43b38e074cc0de2957f10947e376a1d88b9c4dbab340b590800cc1b2e066b2"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ahash 0.8.11",
|
||||
"base64 0.13.1",
|
||||
"bitvec",
|
||||
"chrono",
|
||||
@ -556,6 +617,39 @@ version = "3.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
|
||||
[[package]]
|
||||
name = "byte-unit"
|
||||
version = "5.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ac19bdf0b2665407c39d82dbc937e951e7e2001609f0fb32edd0af45a2d63e"
|
||||
dependencies = [
|
||||
"rust_decimal",
|
||||
"serde",
|
||||
"utf8-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytecheck"
|
||||
version = "0.6.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2"
|
||||
dependencies = [
|
||||
"bytecheck_derive",
|
||||
"ptr_meta",
|
||||
"simdutf8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytecheck_derive"
|
||||
version = "0.6.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.15.0"
|
||||
@ -779,7 +873,7 @@ dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -981,7 +1075,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -991,7 +1085,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1015,7 +1109,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim 0.10.0",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1026,7 +1120,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1073,7 +1167,7 @@ checksum = "377af281d8f23663862a7c84623bc5dcf7f8c44b13c7496a590bdc157f941a43"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@ -1100,7 +1194,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "derive-docs"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"convert_case 0.6.0",
|
||||
@ -1110,7 +1204,7 @@ dependencies = [
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_tokenstream",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1193,7 +1287,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1291,7 +1385,17 @@ checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1367,6 +1471,15 @@ dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fern"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "field-offset"
|
||||
version = "0.3.6"
|
||||
@ -1423,7 +1536,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1539,7 +1652,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1815,7 +1928,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1836,21 +1949,21 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "gltf-derive"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "438ffe1a5540d75403feaf23636b164e816e93f6f03131674722b3886ce32a57"
|
||||
checksum = "14070e711538afba5d6c807edb74bcb84e5dbb9211a3bf5dea0dfab5b24f4c51"
|
||||
dependencies = [
|
||||
"inflections",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gltf-json"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "655951ba557f2bc69ea4b0799446bae281fa78efae6319968bdd2c3e9a06d8e1"
|
||||
checksum = "e6176f9d60a7eab0a877e8e96548605dedbde9190a7ae1e80bbcc1c9af03ab14"
|
||||
dependencies = [
|
||||
"gltf-derive",
|
||||
"serde",
|
||||
@ -1918,7 +2031,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1964,6 +2077,9 @@ name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
dependencies = [
|
||||
"ahash 0.7.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
@ -2420,7 +2536,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.1.53"
|
||||
version = "0.1.55"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx",
|
||||
@ -2479,9 +2595,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddc922f0da3abc22661bf49423c9bfcc02ce6ae92dae007ede6990874789545b"
|
||||
checksum = "2c6e12eb45fd9a28c8e99dbdef54556246b39acee14e4aa6f0fc43636caa62d9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -2524,7 +2640,7 @@ checksum = "0611fc9b9786175da21d895ffa0f65039e19c9111e94a41b7af999e3b95f045f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2658,6 +2774,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"value-bag",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2970,6 +3087,15 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_threads"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oauth2"
|
||||
version = "4.4.2"
|
||||
@ -3236,7 +3362,7 @@ dependencies = [
|
||||
"regex",
|
||||
"regex-syntax 0.7.5",
|
||||
"structmeta 0.2.0",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3250,7 +3376,7 @@ dependencies = [
|
||||
"regex",
|
||||
"regex-syntax 0.8.3",
|
||||
"structmeta 0.3.0",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3392,7 +3518,7 @@ dependencies = [
|
||||
"phf_shared 0.11.2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3460,7 +3586,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3619,6 +3745,26 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1"
|
||||
dependencies = [
|
||||
"ptr_meta_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta_derive"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.31.0"
|
||||
@ -3836,6 +3982,15 @@ version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||
|
||||
[[package]]
|
||||
name = "rend"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c"
|
||||
dependencies = [
|
||||
"bytecheck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.27"
|
||||
@ -4044,6 +4199,35 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rkyv"
|
||||
version = "0.7.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"bytecheck",
|
||||
"bytes",
|
||||
"hashbrown 0.12.3",
|
||||
"ptr_meta",
|
||||
"rend",
|
||||
"rkyv_derive",
|
||||
"seahash",
|
||||
"tinyvec",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rkyv_derive"
|
||||
version = "0.7.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ropey"
|
||||
version = "1.6.1"
|
||||
@ -4054,6 +4238,22 @@ dependencies = [
|
||||
"str_indices",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust_decimal"
|
||||
version = "1.35.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"borsh",
|
||||
"bytes",
|
||||
"num-traits",
|
||||
"rand 0.8.5",
|
||||
"rkyv",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
@ -4224,7 +4424,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4249,6 +4449,12 @@ dependencies = [
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "seahash"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.10.0"
|
||||
@ -4303,9 +4509,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.200"
|
||||
version = "1.0.201"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f"
|
||||
checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@ -4321,13 +4527,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.200"
|
||||
version = "1.0.201"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb"
|
||||
checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4338,7 +4544,7 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4371,7 +4577,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4392,7 +4598,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4434,7 +4640,7 @@ dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4537,6 +4743,12 @@ version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "simdutf8"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.11"
|
||||
@ -4696,7 +4908,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"structmeta-derive 0.2.0",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4708,7 +4920,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"structmeta-derive 0.3.0",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4719,7 +4931,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4730,7 +4942,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4752,7 +4964,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4785,15 +4997,27 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.60"
|
||||
version = "2.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
|
||||
checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn_derive"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "0.1.2"
|
||||
@ -4808,7 +5032,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4938,9 +5162,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "2.0.0-beta.16"
|
||||
version = "2.0.0-beta.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d411ebb670bbe5cf948f6c24978632937329748b499de1619ab55ad31512652"
|
||||
checksum = "5fedd5490eddf117253945f0baedafded43474c971cba546a818f527d5c26266"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -4952,7 +5176,7 @@ dependencies = [
|
||||
"getrandom 0.2.14",
|
||||
"glob",
|
||||
"gtk",
|
||||
"heck 0.4.1",
|
||||
"heck 0.5.0",
|
||||
"http 1.1.0",
|
||||
"jni",
|
||||
"libc",
|
||||
@ -5025,7 +5249,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
"tauri-utils",
|
||||
"thiserror",
|
||||
"time",
|
||||
@ -5043,7 +5267,7 @@ dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
"tauri-codegen",
|
||||
"tauri-utils",
|
||||
]
|
||||
@ -5153,6 +5377,27 @@ dependencies = [
|
||||
"urlpattern",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-log"
|
||||
version = "2.0.0-beta.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97718db0d981b03b7b1257c22f699ff46639220c5acb4510ac9696437afc93f8"
|
||||
dependencies = [
|
||||
"android_logger",
|
||||
"byte-unit",
|
||||
"cocoa",
|
||||
"fern",
|
||||
"log",
|
||||
"objc",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"swift-rs",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-os"
|
||||
version = "2.0.0-beta.3"
|
||||
@ -5231,9 +5476,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime"
|
||||
version = "2.0.0-beta.13"
|
||||
version = "2.0.0-beta.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7439729d0107c9797764919c39c4a4cc3af64306faaa48271da50d8eb4c0283"
|
||||
checksum = "148b6e6aff8e63fe5d4ae1d50159d50cfc0b4309abdeca64833c887c6b5631ef"
|
||||
dependencies = [
|
||||
"dpi",
|
||||
"gtk",
|
||||
@ -5250,9 +5495,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime-wry"
|
||||
version = "2.0.0-beta.13"
|
||||
version = "2.0.0-beta.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c38dcfa7f8c2b2e344c7401972e0ddaaec4fa655666788d94b1852d6c4a7fe8"
|
||||
checksum = "398d065c6e0fbf3c4304583759b6e153bc1e0daeb033bede6834ebe4df371fc3"
|
||||
dependencies = [
|
||||
"cocoa",
|
||||
"gtk",
|
||||
@ -5357,22 +5602,22 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.59"
|
||||
version = "1.0.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
|
||||
checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.59"
|
||||
version = "1.0.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
|
||||
checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5393,7 +5638,9 @@ checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa 1.0.11",
|
||||
"libc",
|
||||
"num-conv",
|
||||
"num_threads",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
@ -5459,7 +5706,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5648,7 +5895,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5677,7 +5924,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5801,7 +6048,7 @@ dependencies = [
|
||||
"Inflector",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
@ -5963,6 +6210,12 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "utf8-width"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
@ -6008,7 +6261,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6017,6 +6270,12 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "value-bag"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101"
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.2.0"
|
||||
@ -6101,7 +6360,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@ -6135,7 +6394,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@ -6276,7 +6535,7 @@ checksum = "ac1345798ecd8122468840bcdf1b95e5dc6d2206c5e4b0eafa078d061f59c9bc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6382,7 +6641,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6393,7 +6652,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6835,7 +7094,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
"syn 2.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -17,6 +17,7 @@ tauri-build = { version = "2.0.0-beta.13", features = [] }
|
||||
anyhow = "1"
|
||||
kcl-lib = { version = "0.1.53", path = "../src/wasm-lib/kcl" }
|
||||
kittycad = "0.3.0"
|
||||
log = "0.4.21"
|
||||
oauth2 = "4.4.2"
|
||||
serde_json = "1.0"
|
||||
tauri = { version = "2.0.0-beta.15", features = [ "devtools", "unstable"] }
|
||||
@ -25,6 +26,7 @@ tauri-plugin-deep-link = { version = "2.0.0-beta.3" }
|
||||
tauri-plugin-dialog = { version = "2.0.0-beta.6" }
|
||||
tauri-plugin-fs = { version = "2.0.0-beta.6" }
|
||||
tauri-plugin-http = { version = "2.0.0-beta.6" }
|
||||
tauri-plugin-log = { version = "2.0.0-beta.4" }
|
||||
tauri-plugin-os = { version = "2.0.0-beta.2" }
|
||||
tauri-plugin-process = { version = "2.0.0-beta.2" }
|
||||
tauri-plugin-shell = { version = "2.0.0-beta.2" }
|
||||
|
@ -9,6 +9,7 @@
|
||||
"permissions": [
|
||||
"cli:default",
|
||||
"deep-link:default",
|
||||
"log:default",
|
||||
"path:default",
|
||||
"event:default",
|
||||
"window:default",
|
||||
|
@ -226,7 +226,7 @@ async fn read_dir_recursive(path: &str) -> Result<FileEntry, InvokeError> {
|
||||
/// The string returned from this method is the access token.
|
||||
#[tauri::command]
|
||||
async fn login(app: tauri::AppHandle, host: &str) -> Result<String, InvokeError> {
|
||||
println!("Logging in...");
|
||||
log::debug!("Logging in...");
|
||||
// Do an OAuth 2.0 Device Authorization Grant dance to get a token.
|
||||
let device_auth_url = oauth2::DeviceAuthorizationUrl::new(format!("{host}/oauth2/device/auth"))
|
||||
.map_err(|e| InvokeError::from_anyhow(e.into()))?;
|
||||
@ -265,7 +265,7 @@ async fn login(app: tauri::AppHandle, host: &str) -> Result<String, InvokeError>
|
||||
// and bypass the shell::open call as it fails on GitHub Actions.
|
||||
let e2e_tauri_enabled = env::var("E2E_TAURI_ENABLED").is_ok();
|
||||
if e2e_tauri_enabled {
|
||||
println!("E2E_TAURI_ENABLED is set, won't open {} externally", auth_uri.secret());
|
||||
log::warn!("E2E_TAURI_ENABLED is set, won't open {} externally", auth_uri.secret());
|
||||
tokio::fs::write("/tmp/kittycad_user_code", details.user_code().secret())
|
||||
.await
|
||||
.map_err(|e| InvokeError::from_anyhow(e.into()))?;
|
||||
@ -308,7 +308,7 @@ async fn get_user(token: &str, hostname: &str) -> Result<kittycad::types::User,
|
||||
baseurl = format!("http://{host}")
|
||||
}
|
||||
}
|
||||
println!("Getting user info...");
|
||||
log::debug!("Getting user info...");
|
||||
|
||||
// use kittycad library to fetch the user info from /user/me
|
||||
let mut client = kittycad::Client::new(token);
|
||||
@ -352,10 +352,12 @@ fn show_in_folder(path: &str) -> Result<(), InvokeError> {
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn open_url_sync(app: &tauri::AppHandle, url: &url::Url) {
|
||||
println!("Opening URL: {:?}", url);
|
||||
log::debug!("Opening URL: {:?}", url);
|
||||
let cloned_url = url.clone();
|
||||
let runner: tauri::async_runtime::JoinHandle<Result<ProjectState>> = tauri::async_runtime::spawn(async move {
|
||||
let url_str = cloned_url.to_string();
|
||||
let url_str = cloned_url.path().to_string();
|
||||
|
||||
log::debug!("Opening URL path : {}", url_str);
|
||||
let path = Path::new(url_str.as_str());
|
||||
ProjectState::new_from_path(path.to_path_buf()).await
|
||||
});
|
||||
@ -367,10 +369,10 @@ fn open_url_sync(app: &tauri::AppHandle, url: &url::Url) {
|
||||
app.manage(state::Store::new(store));
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error opening URL:{} {:?}", url, e);
|
||||
log::warn!("Error opening URL:{} {:?}", url, e);
|
||||
}
|
||||
Ok(Err(e)) => {
|
||||
println!("Error opening URL:{} {:?}", url, e);
|
||||
log::warn!("Error opening URL:{} {:?}", url, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -400,6 +402,15 @@ fn main() -> Result<()> {
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_fs::init())
|
||||
.plugin(tauri_plugin_http::init())
|
||||
.plugin(
|
||||
tauri_plugin_log::Builder::new()
|
||||
.targets([
|
||||
tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Stdout),
|
||||
tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::LogDir { file_name: None }),
|
||||
])
|
||||
.level(log::LevelFilter::Debug)
|
||||
.build(),
|
||||
)
|
||||
.plugin(tauri_plugin_os::init())
|
||||
.plugin(tauri_plugin_process::init())
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
@ -435,7 +446,7 @@ fn main() -> Result<()> {
|
||||
if let Some(source_arg) = matches.args.get("source") {
|
||||
// We don't do an else here because this can be null.
|
||||
if let Some(value) = source_arg.value.as_str() {
|
||||
println!("Got path in cli argument: {}", value);
|
||||
log::info!("Got path in cli argument: {}", value);
|
||||
source_path = Some(Path::new(value).to_path_buf());
|
||||
}
|
||||
}
|
||||
@ -446,7 +457,7 @@ fn main() -> Result<()> {
|
||||
}
|
||||
|
||||
if verbose {
|
||||
println!("Verbose mode enabled.");
|
||||
log::debug!("Verbose mode enabled.");
|
||||
}
|
||||
|
||||
// If we have a source path to open, make sure it exists.
|
||||
@ -476,7 +487,7 @@ fn main() -> Result<()> {
|
||||
|
||||
// Listen on the deep links.
|
||||
app.listen("deep-link://new-url", |event| {
|
||||
println!("got deep-link url: {:?}", event);
|
||||
log::info!("got deep-link url: {:?}", event);
|
||||
// TODO: open_url_sync(app.handle(), event.url);
|
||||
});
|
||||
|
||||
@ -488,10 +499,7 @@ fn main() -> Result<()> {
|
||||
|app, event| {
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
if let tauri::RunEvent::Opened { urls } = event {
|
||||
if let Some(w) = app.get_webview_window("main") {
|
||||
let _ = w.eval(&format!("console.log(`[tauri] Opened URLs: {:?}`)", urls));
|
||||
}
|
||||
println!("Opened URLs: {:?}", urls);
|
||||
log::info!("Opened URLs: {:?}", urls);
|
||||
|
||||
// Handle the first URL.
|
||||
// TODO: do we want to handle more than one URL?
|
||||
|
@ -37,8 +37,7 @@
|
||||
}
|
||||
},
|
||||
"longDescription": "",
|
||||
"macOS": {
|
||||
},
|
||||
"macOS": {},
|
||||
"resources": [],
|
||||
"shortDescription": "",
|
||||
"targets": "all"
|
||||
@ -75,5 +74,5 @@
|
||||
}
|
||||
},
|
||||
"productName": "Zoo Modeling App",
|
||||
"version": "0.20.0"
|
||||
"version": "0.21.4"
|
||||
}
|
||||
|
133
src/Toolbar.tsx
@ -4,7 +4,6 @@ import { engineCommandManager, kclManager } from 'lib/singletons'
|
||||
import { useModelingContext } from 'hooks/useModelingContext'
|
||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||
import { ActionButton } from 'components/ActionButton'
|
||||
import usePlatform from 'hooks/usePlatform'
|
||||
import { isSingleCursorInPipe } from 'lang/queryAst'
|
||||
import { useKclContext } from 'lang/KclProvider'
|
||||
import {
|
||||
@ -12,18 +11,18 @@ import {
|
||||
useNetworkStatus,
|
||||
} from 'components/NetworkHealthIndicator'
|
||||
import { useStore } from 'useStore'
|
||||
import { ActionButtonDropdown } from 'components/ActionButtonDropdown'
|
||||
|
||||
export const Toolbar = () => {
|
||||
const platform = usePlatform()
|
||||
const { commandBarSend } = useCommandsContext()
|
||||
const { state, send, context } = useModelingContext()
|
||||
const toolbarButtonsRef = useRef<HTMLUListElement>(null)
|
||||
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 =
|
||||
'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 =
|
||||
'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(() => {
|
||||
if (!isSingleCursorInPipe(context.selectionRanges, kclManager.ast)) {
|
||||
return false
|
||||
@ -59,10 +58,7 @@ export const Toolbar = () => {
|
||||
{...props}
|
||||
ref={toolbarButtonsRef}
|
||||
onWheel={handleToolbarButtonsWheelEvent}
|
||||
className={
|
||||
'm-0 py-1 rounded-l-sm flex gap-2 items-center overflow-x-auto ' +
|
||||
className
|
||||
}
|
||||
className={'m-0 py-1 rounded-l-sm flex gap-2 items-center ' + className}
|
||||
style={{ scrollbarWidth: 'thin' }}
|
||||
>
|
||||
{state.nextEvents.includes('Enter sketch') && (
|
||||
@ -73,7 +69,7 @@ export const Toolbar = () => {
|
||||
onClick={() =>
|
||||
send({ type: 'Enter sketch', data: { forceNewSketch: true } })
|
||||
}
|
||||
icon={{
|
||||
iconStart={{
|
||||
icon: 'sketch',
|
||||
iconClassName,
|
||||
bgClassName,
|
||||
@ -90,7 +86,7 @@ export const Toolbar = () => {
|
||||
className={buttonClassName}
|
||||
Element="button"
|
||||
onClick={() => send({ type: 'Enter sketch' })}
|
||||
icon={{
|
||||
iconStart={{
|
||||
icon: 'sketch',
|
||||
iconClassName,
|
||||
bgClassName,
|
||||
@ -107,7 +103,7 @@ export const Toolbar = () => {
|
||||
className={buttonClassName}
|
||||
Element="button"
|
||||
onClick={() => send({ type: 'Cancel' })}
|
||||
icon={{
|
||||
iconStart={{
|
||||
icon: 'arrowLeft',
|
||||
iconClassName,
|
||||
bgClassName,
|
||||
@ -130,7 +126,7 @@ export const Toolbar = () => {
|
||||
: send('Equip Line tool')
|
||||
}
|
||||
aria-pressed={state?.matches('Sketch.Line tool')}
|
||||
icon={{
|
||||
iconStart={{
|
||||
icon: 'line',
|
||||
iconClassName,
|
||||
bgClassName,
|
||||
@ -150,7 +146,7 @@ export const Toolbar = () => {
|
||||
: send('Equip tangential arc to')
|
||||
}
|
||||
aria-pressed={state.matches('Sketch.Tangential arc to')}
|
||||
icon={{
|
||||
iconStart={{
|
||||
icon: 'arc',
|
||||
iconClassName,
|
||||
bgClassName,
|
||||
@ -174,7 +170,7 @@ export const Toolbar = () => {
|
||||
: send('Equip rectangle tool')
|
||||
}
|
||||
aria-pressed={state.matches('Sketch.Rectangle tool')}
|
||||
icon={{
|
||||
iconStart={{
|
||||
icon: 'rectangle',
|
||||
iconClassName,
|
||||
bgClassName,
|
||||
@ -196,52 +192,54 @@ export const Toolbar = () => {
|
||||
</>
|
||||
)}
|
||||
{state.matches('Sketch.SketchIdle') &&
|
||||
state.nextEvents
|
||||
.filter(
|
||||
(eventName) =>
|
||||
eventName.includes('Make segment') ||
|
||||
eventName.includes('Constrain')
|
||||
)
|
||||
.sort((a, b) => {
|
||||
const aisEnabled = state.nextEvents
|
||||
.filter((event) => state.can(event as any))
|
||||
.includes(a)
|
||||
const bIsEnabled = state.nextEvents
|
||||
.filter((event) => state.can(event as any))
|
||||
.includes(b)
|
||||
if (aisEnabled && !bIsEnabled) {
|
||||
return -1
|
||||
}
|
||||
if (!aisEnabled && bIsEnabled) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
.map((eventName) => (
|
||||
<li className="contents" key={eventName}>
|
||||
<ActionButton
|
||||
className={buttonClassName}
|
||||
Element="button"
|
||||
key={eventName}
|
||||
onClick={() => send(eventName)}
|
||||
disabled={
|
||||
state.nextEvents.filter(
|
||||
(eventName) =>
|
||||
eventName.includes('Make segment') ||
|
||||
eventName.includes('Constrain')
|
||||
).length > 0 && (
|
||||
<ActionButtonDropdown
|
||||
splitMenuItems={state.nextEvents
|
||||
.filter(
|
||||
(eventName) =>
|
||||
eventName.includes('Make segment') ||
|
||||
eventName.includes('Constrain')
|
||||
)
|
||||
.sort((a, b) => {
|
||||
const aisEnabled = state.nextEvents
|
||||
.filter((event) => state.can(event as any))
|
||||
.includes(a)
|
||||
const bIsEnabled = state.nextEvents
|
||||
.filter((event) => state.can(event as any))
|
||||
.includes(b)
|
||||
if (aisEnabled && !bIsEnabled) {
|
||||
return -1
|
||||
}
|
||||
if (!aisEnabled && bIsEnabled) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
.map((eventName) => ({
|
||||
label: eventName
|
||||
.replace('Make segment ', '')
|
||||
.replace('Constrain ', ''),
|
||||
onClick: () => send(eventName),
|
||||
disabled:
|
||||
!state.nextEvents
|
||||
.filter((event) => state.can(event as any))
|
||||
.includes(eventName) || disableAllButtons
|
||||
}
|
||||
title={eventName}
|
||||
icon={{
|
||||
icon: 'line',
|
||||
iconClassName,
|
||||
bgClassName,
|
||||
}}
|
||||
>
|
||||
{eventName
|
||||
.replace('Make segment ', '')
|
||||
.replace('Constrain ', '')}
|
||||
</ActionButton>
|
||||
</li>
|
||||
))}
|
||||
.includes(eventName) || disableAllButtons,
|
||||
}))}
|
||||
className={buttonClassName}
|
||||
Element="button"
|
||||
iconStart={{
|
||||
icon: 'dimension',
|
||||
iconClassName,
|
||||
bgClassName,
|
||||
}}
|
||||
>
|
||||
Constrain
|
||||
</ActionButtonDropdown>
|
||||
)}
|
||||
{state.matches('idle') && (
|
||||
<li className="contents">
|
||||
<ActionButton
|
||||
@ -259,7 +257,7 @@ export const Toolbar = () => {
|
||||
? 'extrude'
|
||||
: 'sketches need to be closed, or not already extruded'
|
||||
}
|
||||
icon={{
|
||||
iconStart={{
|
||||
icon: 'extrude',
|
||||
iconClassName,
|
||||
bgClassName,
|
||||
@ -274,17 +272,8 @@ export const Toolbar = () => {
|
||||
}
|
||||
|
||||
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="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 />
|
||||
</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>
|
||||
<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">
|
||||
<ToolbarButtons />
|
||||
</menu>
|
||||
)
|
||||
}
|
||||
|
@ -90,7 +90,8 @@ export const ClientSideScene = ({
|
||||
cursor = 'grabbing'
|
||||
} else if (
|
||||
state.matches('Sketch.Line tool') ||
|
||||
state.matches('Sketch.Tangential arc to')
|
||||
state.matches('Sketch.Tangential arc to') ||
|
||||
state.matches('Sketch.Rectangle tool')
|
||||
) {
|
||||
cursor = 'crosshair'
|
||||
} else {
|
||||
@ -104,9 +105,9 @@ export const ClientSideScene = ({
|
||||
style={{ cursor: cursor }}
|
||||
className={`absolute inset-0 h-full w-full transition-all duration-300 ${
|
||||
hideClient ? 'opacity-0' : 'opacity-100'
|
||||
} ${hideServer ? 'bg-black' : ''} ${
|
||||
} ${hideServer ? 'bg-chalkboard-10 dark:bg-chalkboard-100' : ''} ${
|
||||
!hideClient && !hideServer && state.matches('Sketch')
|
||||
? 'bg-black/80'
|
||||
? 'bg-chalkboard-10/80 dark:bg-chalkboard-100/80'
|
||||
: ''
|
||||
}`}
|
||||
></div>
|
||||
|
@ -97,6 +97,7 @@ import {
|
||||
getRectangleCallExpressions,
|
||||
updateRectangleSketch,
|
||||
} from 'lib/rectangleTool'
|
||||
import { getThemeColorForThreeJs } from 'lib/theme'
|
||||
|
||||
type DraftSegment = 'line' | 'tangentialArcTo'
|
||||
|
||||
@ -356,6 +357,7 @@ export class SceneEntities {
|
||||
id: sketchGroup.start.__geoMeta.id,
|
||||
pathToNode: segPathToNode,
|
||||
scale: factor,
|
||||
theme: sceneInfra._theme,
|
||||
})
|
||||
_profileStart.layers.set(SKETCH_LAYER)
|
||||
_profileStart.traverse((child) => {
|
||||
@ -406,6 +408,7 @@ export class SceneEntities {
|
||||
isDraftSegment,
|
||||
scale: factor,
|
||||
texture: sceneInfra.extraSegmentTexture,
|
||||
theme: sceneInfra._theme,
|
||||
})
|
||||
} else {
|
||||
seg = straightSegment({
|
||||
@ -417,6 +420,7 @@ export class SceneEntities {
|
||||
scale: factor,
|
||||
callExpName,
|
||||
texture: sceneInfra.extraSegmentTexture,
|
||||
theme: sceneInfra._theme,
|
||||
})
|
||||
}
|
||||
seg.layers.set(SKETCH_LAYER)
|
||||
@ -964,7 +968,7 @@ export class SceneEntities {
|
||||
if (!draftInfo)
|
||||
// don't want to mod the user's code yet as they have't committed to the change yet
|
||||
// plus this would be the truncated ast being recast, it would be wrong
|
||||
codeManager.updateCodeStateEditor(code)
|
||||
codeManager.updateCodeEditor(code)
|
||||
const { programMemory } = await executeAst({
|
||||
ast: truncatedAst,
|
||||
useFakeExecutor: true,
|
||||
@ -1503,7 +1507,10 @@ export class SceneEntities {
|
||||
const isSelected = parent?.userData?.isSelected
|
||||
colorSegment(
|
||||
selected,
|
||||
isSelected ? 0x0000ff : parent?.userData?.baseColor || 0xffffff
|
||||
isSelected
|
||||
? 0x0000ff
|
||||
: parent?.userData?.baseColor ||
|
||||
getThemeColorForThreeJs(sceneInfra._theme)
|
||||
)
|
||||
const extraSegmentGroup = parent?.getObjectByName(EXTRA_SEGMENT_HANDLE)
|
||||
if (extraSegmentGroup) {
|
||||
|
@ -30,6 +30,7 @@ import { CameraControls } from './CameraControls'
|
||||
import { EngineCommandManager } from 'lang/std/engineConnection'
|
||||
import { settings } from 'lib/settings/initialSettings'
|
||||
import { MouseState } from 'machines/modelingMachine'
|
||||
import { Themes } from 'lib/theme'
|
||||
|
||||
type SendType = ReturnType<typeof useModelingContext>['send']
|
||||
|
||||
@ -101,6 +102,7 @@ export class SceneInfra {
|
||||
isFovAnimationInProgress = false
|
||||
_baseUnit: BaseUnit = 'mm'
|
||||
_baseUnitMultiplier = 1
|
||||
_theme: Themes = Themes.System
|
||||
extraSegmentTexture: Texture
|
||||
lastMouseState: MouseState = { type: 'idle' }
|
||||
onDragStartCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
||||
@ -137,6 +139,9 @@ export class SceneInfra {
|
||||
this._baseUnitMultiplier
|
||||
)
|
||||
}
|
||||
set theme(theme: Themes) {
|
||||
this._theme = theme
|
||||
}
|
||||
resetMouseListeners = () => {
|
||||
this.setCallbacks({
|
||||
onDragStart: () => {},
|
||||
|
@ -37,22 +37,26 @@ import {
|
||||
} from './sceneEntities'
|
||||
import { getTangentPointFromPreviousArc } from 'lib/utils2d'
|
||||
import { ARROWHEAD } from './sceneInfra'
|
||||
import { Themes, getThemeColorForThreeJs } from 'lib/theme'
|
||||
|
||||
export function profileStart({
|
||||
from,
|
||||
id,
|
||||
pathToNode,
|
||||
scale = 1,
|
||||
theme,
|
||||
}: {
|
||||
from: Coords2d
|
||||
id: string
|
||||
pathToNode: PathToNode
|
||||
scale?: number
|
||||
theme: Themes
|
||||
}) {
|
||||
const group = new Group()
|
||||
|
||||
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)
|
||||
|
||||
group.add(mesh)
|
||||
@ -79,6 +83,7 @@ export function straightSegment({
|
||||
scale = 1,
|
||||
callExpName,
|
||||
texture,
|
||||
theme,
|
||||
}: {
|
||||
from: Coords2d
|
||||
to: Coords2d
|
||||
@ -88,6 +93,7 @@ export function straightSegment({
|
||||
scale?: number
|
||||
callExpName: string
|
||||
texture: Texture
|
||||
theme: Themes
|
||||
}): 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 mesh = new Mesh(geometry, body)
|
||||
mesh.userData.type = isDraftSegment
|
||||
@ -134,7 +141,7 @@ export function straightSegment({
|
||||
const length = Math.sqrt(
|
||||
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)
|
||||
const dir = new Vector3()
|
||||
.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)
|
||||
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])
|
||||
.normalize()
|
||||
.multiplyScalar(EXTRA_SEGMENT_OFFSET_PX * scale)
|
||||
@ -162,8 +169,10 @@ export function straightSegment({
|
||||
return group
|
||||
}
|
||||
|
||||
function createArrowhead(scale = 1): Group {
|
||||
const arrowMaterial = new MeshBasicMaterial({ color: 0xffffff })
|
||||
function createArrowhead(scale = 1, theme: Themes): Group {
|
||||
const arrowMaterial = new MeshBasicMaterial({
|
||||
color: getThemeColorForThreeJs(theme),
|
||||
})
|
||||
// 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
|
||||
const arrowheadMesh = new Mesh(new ConeGeometry(4.5, 20, 12), arrowMaterial)
|
||||
@ -179,7 +188,11 @@ function createArrowhead(scale = 1): Group {
|
||||
return arrowGroup
|
||||
}
|
||||
|
||||
function createExtraSegmentHandle(scale: number, texture: Texture): Group {
|
||||
function createExtraSegmentHandle(
|
||||
scale: number,
|
||||
texture: Texture,
|
||||
theme: Themes
|
||||
): Group {
|
||||
const particleMaterial = new PointsMaterial({
|
||||
size: 12, // in pixels
|
||||
map: texture,
|
||||
@ -189,7 +202,7 @@ function createExtraSegmentHandle(scale: number, texture: Texture): Group {
|
||||
})
|
||||
const mat = new MeshBasicMaterial({
|
||||
transparent: true,
|
||||
color: 0xffffff,
|
||||
color: getThemeColorForThreeJs(theme),
|
||||
opacity: 0,
|
||||
})
|
||||
const particleGeometry = new BufferGeometry().setFromPoints([
|
||||
@ -218,6 +231,7 @@ export function tangentialArcToSegment({
|
||||
isDraftSegment,
|
||||
scale = 1,
|
||||
texture,
|
||||
theme,
|
||||
}: {
|
||||
prevSegment: SketchGroup['value'][number]
|
||||
from: Coords2d
|
||||
@ -227,6 +241,7 @@ export function tangentialArcToSegment({
|
||||
isDraftSegment?: boolean
|
||||
scale?: number
|
||||
texture: Texture
|
||||
theme: Themes
|
||||
}): Group {
|
||||
const group = new Group()
|
||||
|
||||
@ -257,7 +272,8 @@ export function tangentialArcToSegment({
|
||||
scale,
|
||||
})
|
||||
|
||||
const body = new MeshBasicMaterial({ color: 0xffffff })
|
||||
const baseColor = getThemeColorForThreeJs(theme)
|
||||
const body = new MeshBasicMaterial({ color: baseColor })
|
||||
const mesh = new Mesh(geometry, body)
|
||||
mesh.userData.type = isDraftSegment
|
||||
? TANGENTIAL_ARC_TO__SEGMENT_DASH
|
||||
@ -271,10 +287,11 @@ export function tangentialArcToSegment({
|
||||
prevSegment,
|
||||
pathToNode,
|
||||
isSelected: false,
|
||||
baseColor,
|
||||
}
|
||||
group.name = TANGENTIAL_ARC_TO_SEGMENT
|
||||
|
||||
const arrowGroup = createArrowhead(scale)
|
||||
const arrowGroup = createArrowhead(scale, theme)
|
||||
arrowGroup.position.set(to[0], to[1], 0)
|
||||
const arrowheadAngle = endAngle + (Math.PI / 2) * (ccw ? 1 : -1)
|
||||
arrowGroup.quaternion.setFromUnitVectors(
|
||||
@ -285,7 +302,7 @@ export function tangentialArcToSegment({
|
||||
const shouldHide = pxLength < HIDE_SEGMENT_LENGTH
|
||||
arrowGroup.visible = !shouldHide
|
||||
|
||||
const extraSegmentGroup = createExtraSegmentHandle(scale, texture)
|
||||
const extraSegmentGroup = createExtraSegmentHandle(scale, texture, theme)
|
||||
const circumferenceInPx = (2 * Math.PI * radius) / scale
|
||||
const extraSegmentAngleDelta =
|
||||
(EXTRA_SEGMENT_OFFSET_PX / circumferenceInPx) * Math.PI * 2
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { ActionIcon, ActionIconProps } from './ActionIcon'
|
||||
import React from 'react'
|
||||
import React, { ForwardedRef, forwardRef } from 'react'
|
||||
import { paths } from 'lib/paths'
|
||||
import { Link } from 'react-router-dom'
|
||||
import type { LinkProps } from 'react-router-dom'
|
||||
|
||||
interface BaseActionButtonProps {
|
||||
icon?: ActionIconProps
|
||||
iconStart?: ActionIconProps
|
||||
iconEnd?: ActionIconProps
|
||||
className?: string
|
||||
}
|
||||
|
||||
@ -32,15 +33,15 @@ type ActionButtonAsElement = BaseActionButtonProps &
|
||||
Element: React.ComponentType<React.HTMLAttributes<HTMLButtonElement>>
|
||||
}
|
||||
|
||||
type ActionButtonProps =
|
||||
export type ActionButtonProps =
|
||||
| ActionButtonAsButton
|
||||
| ActionButtonAsLink
|
||||
| ActionButtonAsExternal
|
||||
| ActionButtonAsElement
|
||||
|
||||
export const ActionButton = (props: ActionButtonProps) => {
|
||||
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 ${
|
||||
props.icon ? 'pr-2' : 'px-2'
|
||||
export const ActionButton = forwardRef((props: ActionButtonProps, ref) => {
|
||||
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.iconStart ? (props.iconEnd ? 'px-0' : 'pr-2') : 'px-2'
|
||||
} ${props.className ? props.className : ''}`
|
||||
|
||||
switch (props.Element) {
|
||||
@ -48,11 +49,23 @@ export const ActionButton = (props: ActionButtonProps) => {
|
||||
// Note we have to destructure 'className' and 'Element' out of props
|
||||
// because we don't want to pass them to the button element;
|
||||
// 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 (
|
||||
<button className={classNames} {...rest}>
|
||||
{props.icon && <ActionIcon {...icon} />}
|
||||
<button
|
||||
ref={ref as ForwardedRef<HTMLButtonElement>}
|
||||
className={classNames}
|
||||
{...rest}
|
||||
>
|
||||
{iconStart && <ActionIcon {...iconStart} />}
|
||||
{children}
|
||||
{iconEnd && <ActionIcon {...iconEnd} />}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
@ -60,15 +73,22 @@ export const ActionButton = (props: ActionButtonProps) => {
|
||||
const {
|
||||
Element,
|
||||
to,
|
||||
icon,
|
||||
iconStart,
|
||||
iconEnd,
|
||||
children,
|
||||
className: _className,
|
||||
...rest
|
||||
} = props
|
||||
return (
|
||||
<Link to={to || paths.INDEX} className={classNames} {...rest}>
|
||||
{icon && <ActionIcon {...icon} />}
|
||||
<Link
|
||||
ref={ref as ForwardedRef<HTMLAnchorElement>}
|
||||
to={to || paths.INDEX}
|
||||
className={classNames}
|
||||
{...rest}
|
||||
>
|
||||
{iconStart && <ActionIcon {...iconStart} />}
|
||||
{children}
|
||||
{iconEnd && <ActionIcon {...iconEnd} />}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
@ -76,33 +96,42 @@ export const ActionButton = (props: ActionButtonProps) => {
|
||||
const {
|
||||
Element,
|
||||
to,
|
||||
icon,
|
||||
iconStart,
|
||||
iconEnd,
|
||||
children,
|
||||
className: _className,
|
||||
...rest
|
||||
} = props
|
||||
return (
|
||||
<Link
|
||||
ref={ref as ForwardedRef<HTMLAnchorElement>}
|
||||
to={to || paths.INDEX}
|
||||
className={classNames}
|
||||
{...rest}
|
||||
target="_blank"
|
||||
>
|
||||
{icon && <ActionIcon {...icon} />}
|
||||
{iconStart && <ActionIcon {...iconStart} />}
|
||||
{children}
|
||||
{iconEnd && <ActionIcon {...iconEnd} />}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
default: {
|
||||
const { Element, icon, children, className: _className, ...rest } = props
|
||||
if (!Element) throw new Error('Element is required')
|
||||
const {
|
||||
Element,
|
||||
iconStart,
|
||||
children,
|
||||
className: _className,
|
||||
...rest
|
||||
} = props
|
||||
|
||||
return (
|
||||
<Element className={classNames} {...rest}>
|
||||
{props.icon && <ActionIcon {...props.icon} />}
|
||||
{props.iconStart && <ActionIcon {...props.iconStart} />}
|
||||
{children}
|
||||
{props.iconEnd && <ActionIcon {...props.iconEnd} />}
|
||||
</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',
|
||||
children,
|
||||
}: ActionIconProps) => {
|
||||
// By default, we reverse the icon color and background color in dark mode
|
||||
const computedIconClassName = `h-auto text-primary dark:text-current !group-disabled:text-chalkboard-60 !group-disabled:text-chalkboard-60 ${iconClassName}`
|
||||
|
||||
const computedBgClassName = `bg-primary/10 dark:bg-chalkboard-90 !group-disabled:bg-chalkboard-30 !dark:group-disabled:bg-chalkboard-80 ${bgClassName}`
|
||||
const computedIconClassName = `h-auto text-inherit 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}`
|
||||
|
||||
return (
|
||||
<div
|
||||
|