diff --git a/e2e/playwright/testing-settings.spec.ts b/e2e/playwright/testing-settings.spec.ts index 8a6e7b245..df273b05e 100644 --- a/e2e/playwright/testing-settings.spec.ts +++ b/e2e/playwright/testing-settings.spec.ts @@ -552,4 +552,70 @@ test.describe('Testing settings', () => { await changeUnitOfMeasureInGizmo('m', 'Meters') }) }) + + test('Changing theme in sketch mode', async ({ page }) => { + const u = await getUtils(page) + await page.addInitScript(() => { + localStorage.setItem( + 'persistCode', + `const sketch001 = startSketchOn('XZ') + |> startProfileAt([0, 0], %) + |> line([5, 0], %) + |> line([0, 5], %) + |> line([-5, 0], %) + |> lineTo([profileStartX(%), profileStartY(%)], %) + |> close(%) +const extrude001 = extrude(5, sketch001) +` + ) + }) + await page.setViewportSize({ width: 1200, height: 500 }) + + // Selectors and constants + const editSketchButton = page.getByRole('button', { name: 'Edit Sketch' }) + const lineToolButton = page.getByTestId('line') + const segmentOverlays = page.getByTestId('segment-overlay') + const sketchOriginLocation = { x: 600, y: 250 } + const darkThemeSegmentColor: [number, number, number] = [215, 215, 215] + const lightThemeSegmentColor: [number, number, number] = [90, 90, 90] + + await test.step(`Get into sketch mode`, async () => { + await u.waitForAuthSkipAppStart() + await page.mouse.click(700, 200) + await expect(editSketchButton).toBeVisible() + await editSketchButton.click() + + // We use the line tool as a proxy for sketch mode + await expect(lineToolButton).toBeVisible() + await expect(segmentOverlays).toHaveCount(4) + // but we allow more time to pass for animating to the sketch + await page.waitForTimeout(1000) + }) + + await test.step(`Check the sketch line color before`, async () => { + await expect + .poll(() => + u.getGreatestPixDiff(sketchOriginLocation, darkThemeSegmentColor) + ) + .toBeLessThan(15) + }) + + await test.step(`Change theme to light using command palette`, async () => { + await page.keyboard.press('ControlOrMeta+K') + await page.getByRole('option', { name: 'theme' }).click() + await page.getByRole('option', { name: 'light' }).click() + await expect(page.getByText('theme to "light"')).toBeVisible() + + // Make sure we haven't left sketch mode + await expect(lineToolButton).toBeVisible() + }) + + await test.step(`Check the sketch line color after`, async () => { + await expect + .poll(() => + u.getGreatestPixDiff(sketchOriginLocation, lightThemeSegmentColor) + ) + .toBeLessThan(15) + }) + }) }) diff --git a/src/clientSideScene/sceneEntities.ts b/src/clientSideScene/sceneEntities.ts index 8399202a6..8d09e78a8 100644 --- a/src/clientSideScene/sceneEntities.ts +++ b/src/clientSideScene/sceneEntities.ts @@ -102,7 +102,7 @@ import { getRectangleCallExpressions, updateRectangleSketch, } from 'lib/rectangleTool' -import { getThemeColorForThreeJs } from 'lib/theme' +import { getThemeColorForThreeJs, Themes } from 'lib/theme' import { err, reportRejection, trap } from 'lib/trap' import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer' import { Point3d } from 'wasm-lib/kcl/bindings/Point3d' @@ -1473,6 +1473,25 @@ export class SceneEntities { to, }) } + /** + * Update the base color of each of the THREEjs meshes + * that represent each of the sketch segments, to get the + * latest value from `sceneInfra._theme` + */ + updateSegmentBaseColor(newColor: Themes.Light | Themes.Dark) { + const newColorThreeJs = getThemeColorForThreeJs(newColor) + Object.values(this.activeSegments).forEach((group) => { + group.userData.baseColor = newColorThreeJs + group.traverse((child) => { + if ( + child instanceof Mesh && + child.material instanceof MeshBasicMaterial + ) { + child.material.color.set(newColorThreeJs) + } + }) + }) + } removeSketchGrid() { if (this.axisGroup) this.scene.remove(this.axisGroup) } diff --git a/src/components/SettingsAuthProvider.tsx b/src/components/SettingsAuthProvider.tsx index feb27a601..10bc6f96a 100644 --- a/src/components/SettingsAuthProvider.tsx +++ b/src/components/SettingsAuthProvider.tsx @@ -17,7 +17,12 @@ import decamelize from 'decamelize' import { Actor, AnyStateMachine, ContextFrom, Prop, StateFrom } from 'xstate' import { isDesktop } from 'lib/isDesktop' import { authCommandBarConfig } from 'lib/commandBarConfigs/authCommandConfig' -import { kclManager, sceneInfra, engineCommandManager } from 'lib/singletons' +import { + kclManager, + sceneInfra, + engineCommandManager, + sceneEntitiesManager, +} from 'lib/singletons' import { uuidv4 } from 'lib/utils' import { IndexLoaderData } from 'lib/types' import { settings } from 'lib/settings/initialSettings' @@ -137,6 +142,7 @@ export const SettingsAuthProviderBase = ({ setClientTheme: ({ context }) => { const opposingTheme = getOppositeTheme(context.app.theme.current) sceneInfra.theme = opposingTheme + sceneEntitiesManager.updateSegmentBaseColor(opposingTheme) }, setEngineEdges: ({ context }) => { // eslint-disable-next-line @typescript-eslint/no-floating-promises