From 8883df34455e9177523ee9a29a92236362aefe7e Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Mon, 2 Aug 2021 22:48:59 +1000 Subject: [PATCH 01/19] Add the beginnings of the customizer UI Relates to #320 --- .vscode/settings.json | 1 + .../src/components/Customizer/Customizer.tsx | 68 +++++++++++++++++++ .../src/components/IdeViewer/IdeViewer.tsx | 2 + 3 files changed, 71 insertions(+) create mode 100644 app/web/src/components/Customizer/Customizer.tsx diff --git a/.vscode/settings.json b/.vscode/settings.json index d71538b..e9d5f61 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "cSpell.words": [ + "Customizer", "Hutten", "cadquery", "jscad", diff --git a/app/web/src/components/Customizer/Customizer.tsx b/app/web/src/components/Customizer/Customizer.tsx new file mode 100644 index 0000000..e89633d --- /dev/null +++ b/app/web/src/components/Customizer/Customizer.tsx @@ -0,0 +1,68 @@ +import { useRender } from 'src/components/IdeWrapper/useRender' + +const Customizer = () => { + const [open, setOpen] = React.useState(true) + const ref = React.useRef() + const jsCadCustomizerElement = ref.current + React.useEffect(() => { + console.log(jsCadCustomizerElement) + if (jsCadCustomizerElement) { + jsCadCustomizerElement.innerHTML = `
hi there
` + } + }, [jsCadCustomizerElement]) + const handleRender = useRender() + return ( +
+
+
+ +
Parameters
+
+ +
+
+
+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+

lots of lines should cause scroll

+
+
+
+ ) +} + +export default Customizer diff --git a/app/web/src/components/IdeViewer/IdeViewer.tsx b/app/web/src/components/IdeViewer/IdeViewer.tsx index 8930b9f..0ac5421 100644 --- a/app/web/src/components/IdeViewer/IdeViewer.tsx +++ b/app/web/src/components/IdeViewer/IdeViewer.tsx @@ -6,6 +6,7 @@ import { Vector3 } from 'three' import { requestRender } from 'src/helpers/hooks/useIdeState' import texture from './dullFrontLitMetal.png' import { TextureLoader } from 'three/src/loaders/TextureLoader' +import Customizer from 'src/components/Customizer/Customizer' const loader = new TextureLoader() const colorMap = loader.load(texture) @@ -243,6 +244,7 @@ const IdeViewer = ({ Loading }) => {
)} + ) } From 336501aaffc07cf360c3a031e53ee596dc43d261 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Mon, 2 Aug 2021 23:19:57 +1000 Subject: [PATCH 02/19] add customizerParams to state --- .../src/components/Customizer/Customizer.tsx | 31 ++++++++++++++----- app/web/src/helpers/cadPackages/common.ts | 4 +++ .../helpers/cadPackages/jsCadController.ts | 1 + app/web/src/helpers/hooks/useIdeState.ts | 11 +++++-- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/app/web/src/components/Customizer/Customizer.tsx b/app/web/src/components/Customizer/Customizer.tsx index e89633d..84da796 100644 --- a/app/web/src/components/Customizer/Customizer.tsx +++ b/app/web/src/components/Customizer/Customizer.tsx @@ -1,24 +1,41 @@ import { useRender } from 'src/components/IdeWrapper/useRender' +import { useIdeContext } from 'src/helpers/hooks/useIdeContext' const Customizer = () => { const [open, setOpen] = React.useState(true) const ref = React.useRef() const jsCadCustomizerElement = ref.current + const { state } = useIdeContext() + const customizerParams = state?.objectData?.customizerParams + console.log(state) React.useEffect(() => { - console.log(jsCadCustomizerElement) - if (jsCadCustomizerElement) { - jsCadCustomizerElement.innerHTML = `
hi there
` + console.log({ jsCadCustomizerElement, customizerParams }) + if (jsCadCustomizerElement && customizerParams) { + jsCadCustomizerElement.innerHTML = `
${JSON.stringify( + customizerParams + )}
` } - }, [jsCadCustomizerElement]) + }, [jsCadCustomizerElement, customizerParams]) const handleRender = useRender() return ( -
+
- +
Parameters
- +
diff --git a/app/web/src/helpers/cadPackages/common.ts b/app/web/src/helpers/cadPackages/common.ts index cbe789a..3f5480c 100644 --- a/app/web/src/helpers/cadPackages/common.ts +++ b/app/web/src/helpers/cadPackages/common.ts @@ -30,6 +30,7 @@ export interface HealthyResponse { data: any type: 'stl' | 'png' | 'geometry' } + customizerParams?: any } export function createHealthyResponse({ @@ -37,11 +38,13 @@ export function createHealthyResponse({ data, consoleMessage, type, + customizerParams, }: { date: Date data: any consoleMessage: string type: HealthyResponse['objectData']['type'] + customizerParams?: any }): HealthyResponse { return { status: 'healthy', @@ -54,6 +57,7 @@ export function createHealthyResponse({ message: consoleMessage, time: date, }, + customizerParams, } } diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index e26f92e..02d7124 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -108,6 +108,7 @@ self.addEventListener('message', (e)=>worker.postMessage(e.data)) data: [...data.entities.map(CSG2Object3D).filter((o) => o)], consoleMessage: data.scriptStats, date: new Date(), + customizerParams: ['param1', 'abc'], }) } callResolve() diff --git a/app/web/src/helpers/hooks/useIdeState.ts b/app/web/src/helpers/hooks/useIdeState.ts index 9b671be..9f5e68c 100644 --- a/app/web/src/helpers/hooks/useIdeState.ts +++ b/app/web/src/helpers/hooks/useIdeState.ts @@ -89,6 +89,7 @@ export interface State { type: 'INIT' | 'stl' | 'png' | 'geometry' data: any quality: 'low' | 'high' + customizerParams?: any } layout: any camera: { @@ -153,6 +154,7 @@ export const useIdeState = (): [State, (actionOrThunk: any) => any] => { ...state.objectData, type: payload.objectData?.type, data: payload.objectData?.data, + customizerParams: payload.customizerParams, }, consoleMessages: payload.message ? [...state.consoleMessages, payload.message] @@ -248,7 +250,7 @@ export const requestRender = ({ quality, }, }) - .then(({ objectData, message, status }) => { + .then(({ objectData, message, status, customizerParams }) => { if (status === 'error') { dispatch({ type: 'errorRender', @@ -257,7 +259,12 @@ export const requestRender = ({ } else { dispatch({ type: 'healthyRender', - payload: { objectData, message, lastRunCode: code }, + payload: { + objectData, + message, + lastRunCode: code, + customizerParams, + }, }) return objectData } From 77ee959c431f9397726e5e1eaf83043b74954a2b Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Mon, 2 Aug 2021 23:24:26 +0200 Subject: [PATCH 03/19] working somewhat ok --- app/web/public/demo-worker.js | 4 +- .../src/components/Customizer/Customizer.tsx | 25 +-- .../src/components/IdeWrapper/useRender.ts | 3 +- app/web/src/helpers/cadPackages/common.ts | 7 +- .../helpers/cadPackages/jsCadController.ts | 61 +++++-- .../src/helpers/cadPackages/jscadParams.js | 169 ++++++++++++++++++ app/web/src/helpers/hooks/useIdeState.ts | 20 ++- 7 files changed, 253 insertions(+), 36 deletions(-) create mode 100644 app/web/src/helpers/cadPackages/jscadParams.js diff --git a/app/web/public/demo-worker.js b/app/web/public/demo-worker.js index ebbb97c..d8b18eb 100644 --- a/app/web/public/demo-worker.js +++ b/app/web/public/demo-worker.js @@ -246,6 +246,8 @@ const makeScriptWorker = ({callback, convertToSolids})=>{ function runMain(params={}){ let time = Date.now() let solids + let transfer = [] + console.log('run main') try{ solids = main(params) }catch(e){ @@ -255,7 +257,6 @@ const makeScriptWorker = ({callback, convertToSolids})=>{ let solidsTime = Date.now() - time scriptStats = `generate solids ${solidsTime}ms` - let transfer = [] if(convertToSolids === 'buffers'){ CSGToBuffers.clearCache() entities = solids.map((csg)=>{ @@ -549,6 +550,7 @@ return (params)=>{ workerBaseURI = baseURI const sendCmd = (params, transfer)=>{ + console.log('sendCmd', params.worker, params.action, params) if(params.worker === 'render') sendToRender(params, transfer) else if(params.worker === 'script') diff --git a/app/web/src/components/Customizer/Customizer.tsx b/app/web/src/components/Customizer/Customizer.tsx index 84da796..513220d 100644 --- a/app/web/src/components/Customizer/Customizer.tsx +++ b/app/web/src/components/Customizer/Customizer.tsx @@ -1,5 +1,6 @@ -import { useRender } from 'src/components/IdeWrapper/useRender' +import { useRender, } from 'src/components/IdeWrapper/useRender' import { useIdeContext } from 'src/helpers/hooks/useIdeContext' +import { genParams, getParams } from 'src/helpers/cadPackages/jscadParams' const Customizer = () => { const [open, setOpen] = React.useState(true) @@ -7,16 +8,18 @@ const Customizer = () => { const jsCadCustomizerElement = ref.current const { state } = useIdeContext() const customizerParams = state?.objectData?.customizerParams - console.log(state) - React.useEffect(() => { - console.log({ jsCadCustomizerElement, customizerParams }) - if (jsCadCustomizerElement && customizerParams) { - jsCadCustomizerElement.innerHTML = `
${JSON.stringify( - customizerParams - )}
` - } - }, [jsCadCustomizerElement, customizerParams]) + const lastParameters = state?.objectData?.lastParameters const handleRender = useRender() + const handleRender2 = ()=>handleRender(getParams(ref.current)) + + React.useEffect(() => { + console.log({ jsCadCustomizerElement, customizerParams, lastParameters }) + if (jsCadCustomizerElement && customizerParams) { + genParams(customizerParams, jsCadCustomizerElement, lastParameters || {}, (values)=>{ + handleRender(values) + },[]) + } + }, [jsCadCustomizerElement, customizerParams, lastParameters]) return (
{
diff --git a/app/web/src/components/IdeWrapper/useRender.ts b/app/web/src/components/IdeWrapper/useRender.ts index bc82f81..52d233d 100644 --- a/app/web/src/components/IdeWrapper/useRender.ts +++ b/app/web/src/components/IdeWrapper/useRender.ts @@ -3,7 +3,7 @@ import { useIdeContext } from 'src/helpers/hooks/useIdeContext' export const useRender = () => { const { state, thunkDispatch } = useIdeContext() - return () => { + return (parameters) => { thunkDispatch((dispatch, getState) => { const state = getState() dispatch({ type: 'setLoading' }) @@ -13,6 +13,7 @@ export const useRender = () => { code: state.code, viewerSize: state.viewerSize, camera: state.camera, + parameters, }) }) localStorage.setItem(makeCodeStoreKey(state.ideType), state.code) diff --git a/app/web/src/helpers/cadPackages/common.ts b/app/web/src/helpers/cadPackages/common.ts index 3f5480c..5dab46d 100644 --- a/app/web/src/helpers/cadPackages/common.ts +++ b/app/web/src/helpers/cadPackages/common.ts @@ -12,6 +12,7 @@ export const stlToGeometry = (url) => export interface RenderArgs { code: State['code'] + parameters: any, settings: { camera: State['camera'] viewerSize: State['viewerSize'] @@ -31,6 +32,7 @@ export interface HealthyResponse { type: 'stl' | 'png' | 'geometry' } customizerParams?: any + lastParameters?: any } export function createHealthyResponse({ @@ -39,12 +41,14 @@ export function createHealthyResponse({ consoleMessage, type, customizerParams, -}: { + lastParameters, + }: { date: Date data: any consoleMessage: string type: HealthyResponse['objectData']['type'] customizerParams?: any + lastParameters?: any }): HealthyResponse { return { status: 'healthy', @@ -58,6 +62,7 @@ export function createHealthyResponse({ time: date, }, customizerParams, + lastParameters, } } diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index 02d7124..6178899 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -70,6 +70,7 @@ function CSG2Object3D(obj) { } let scriptWorker +let lastParameters = {} const scriptUrl = '/demo-worker.js' let resolveReference = null let response = null @@ -81,50 +82,73 @@ const callResolve = () => { export const render: DefaultKernelExport['render'] = async ({ code, + parameters, settings, }: RenderArgs) => { if (!scriptWorker) { + console.trace('************************** creating new worker ************************') const baseURI = document.baseURI.toString() const script = `let baseURI = '${baseURI}' -importScripts(new URL('${scriptUrl}',baseURI)) -let worker = jscadWorker({ - baseURI: baseURI, - scope:'worker', - convertToSolids: 'buffers', - callback:(params)=>self.postMessage(params), -}) -self.addEventListener('message', (e)=>worker.postMessage(e.data)) -` + importScripts(new URL('${scriptUrl}',baseURI)) + let worker = jscadWorker({ + baseURI: baseURI, + scope:'worker', + convertToSolids: 'buffers', + callback:(params)=>self.postMessage(params), + }) + self.addEventListener('message', (e)=>worker.postMessage(e.data)) + ` const blob = new Blob([script], { type: 'text/javascript' }) scriptWorker = new Worker(window.URL.createObjectURL(blob)) + let parameterDefinitions = [] scriptWorker.addEventListener('message', (e) => { const data = e.data - if (data.action == 'entities') { + if (data.action == 'parameterDefinitions') { + console.log('message',data) + parameterDefinitions = data.data + } else if (data.action == 'entities') { if (data.error) { response = createUnhealthyResponse(new Date(), data.error) } else { + console.log('lastParameters',lastParameters) response = createHealthyResponse({ type: 'geometry', data: [...data.entities.map(CSG2Object3D).filter((o) => o)], consoleMessage: data.scriptStats, date: new Date(), - customizerParams: ['param1', 'abc'], + customizerParams: parameterDefinitions, + lastParameters, }) } callResolve() } }) - + callResolve() response = null scriptWorker.postMessage({ action: 'init', baseURI, alias: [] }) } - scriptWorker.postMessage({ - action: 'runScript', - worker: 'script', - script: code, - url: 'jscad_script', - }) + + if(parameters){ + // we are not evaluating code, but reacting to parameters change + scriptWorker.postMessage({ + action: 'updateParams', + worker: 'script', + params: parameters, + }) + }else{ + scriptWorker.postMessage({ + action: 'runScript', + worker: 'script', + script: code, + params: parameters || {}, + url: 'jscad_script', + }) + } + // we need this to keep the form filled with same data when new parameter definitions arrive + // each render of the script could provide new paramaters. In case some of them are still rpesent + // it is expected for them to stay the same and not just reset + lastParameters = parameters || {} const waitResult = new Promise((resolve) => { resolveReference = resolve @@ -132,6 +156,7 @@ self.addEventListener('message', (e)=>worker.postMessage(e.data)) await waitResult resolveReference = null + if(parameters) delete response.customizerParams return response } diff --git a/app/web/src/helpers/cadPackages/jscadParams.js b/app/web/src/helpers/cadPackages/jscadParams.js new file mode 100644 index 0000000..c72e80d --- /dev/null +++ b/app/web/src/helpers/cadPackages/jscadParams.js @@ -0,0 +1,169 @@ +const GROUP_SELECTOR = 'DIV[type="group"] LABEL' +const INPUT_SELECTOR = 'INPUT, SELECT' + +function forEachInput(target, callback){ + target.querySelectorAll(INPUT_SELECTOR).forEach(callback) +} + +function forEachGroup(target, callback){ + target.querySelectorAll(GROUP_SELECTOR).forEach(callback) +} + +const numeric = {number:1, float:1, int:1, range:1, slider:1} + +function applyRange(inp){ + let label = inp.previousElementSibling + if(label.tagName == 'LABEL'){ + let info = label.querySelector('I') + if(info) info.innerHTML = '('+inp.value+')' + } +} + +export function genParams(defs, target, storedParams={}, callback=undefined, buttons=['reset','save','load','edit','link']){ + + let funcs = { + group:function({name,type, caption, captions, value, min,max}){ + return '' + }, + choice:function({name,type, caption, captions, value, values, min, max}){ + if(!captions) captions = values + + let ret = `' + }, + float: inputNumber, + range: inputNumber, + slider: inputNumber, + int: inputNumber, + text: inputNumber, + url: inputNumber, + email: inputNumber, + date: inputNumber, + password: inputNumber, + color: inputNumber, + // TODO radio similar options as choice + checkbox :function({name,type, caption, captions, value, checked, min,max}){ + let checkedStr = (value === 'checked' || value === true) ? 'checked':'' + return `` + }, + number: inputNumber, + } + + function inputNumber(def){ + let {name,type, caption, captions, value, min,max, step, placeholder, live} = def + if(value === null || value === undefined) value = numeric[type] ? 0:''; + let inputType = type + if(type == 'int' || type=='float') inputType = 'number' + if(type == 'range' || type=='slider') inputType = 'range' + var str = `'; + } + + let html = ''; + let closed = false + let missing = {} + + defs.forEach(def=>{ + let {type, caption, name} = def + + if(storedParams[name] !== undefined){ + def.value = storedParams[name]; + }else { + def.value = def.initial || def['default'] || def.checked + } + + if(type == 'group'){ + closed = def.value == 'closed' + } + def.closed = closed + + html +=`
` + + html += `` + if(type == 'checkbox') html += funcs[type](def) + html += `${caption}` + + if(funcs[type] && type != 'checkbox') html += funcs[type](def) + + if(!funcs[type]) missing[type] = 1 + + html +='
\n' + }) + + let missingKeys = Object.keys(missing) + if(missingKeys.length) console.log('missing param impl',missingKeys); + + function _callback(saveOnly){ + if(callback) callback(getParams(target)) + } + + html +='
' + buttons.forEach(b=>{ + if(typeof b === 'string') b = {id:b, name:b} + let {id,name} = b + html += `` + }) + html += '
' + + target.innerHTML = html + + forEachInput(target, inp=>{ + let type = inp.type + inp.addEventListener('input', function(evt){ + applyRange(inp) + if(inp.getAttribute('live') == '1') _callback(); + }) + if(inp.getAttribute('live') != '1') inp.addEventListener('change', _callback) + + }) + + function groupClick(evt){ + var groupDiv = evt.target.parentNode + var closed = (groupDiv.getAttribute('closed') == '1') ? '0':'1' + var name = evt.target.getAttribute('name') + do{ + groupDiv.setAttribute('closed', closed) + groupDiv = groupDiv.nextElementSibling + }while(groupDiv && groupDiv.getAttribute('type') != 'group') + callback(getParams(target),true) + } + + forEachGroup(target, label=>label.onclick=groupClick) +} + +export function getParams(target){ + let params = {} + if(!target) return params + + forEachGroup(target,elem=>{ + let name = elem.getAttribute('name') + params[name] = (groupDiv.getAttribute('closed') == '1') ? 'closed':'' + }) + + forEachInput(target,elem=>{ + let name = elem.name + let value = elem.value + if(elem.tagName == 'INPUT'){ + if(elem.type == 'checkbox') value = elem.checked + if(elem.type == 'range' || elem.type == 'color') applyRange(elem) + } + + if(numeric[elem.getAttribute('type')] || elem.getAttribute('numeric') == '1') value = parseFloat(value || 0) + params[name] = value + }) + return params; +} + diff --git a/app/web/src/helpers/hooks/useIdeState.ts b/app/web/src/helpers/hooks/useIdeState.ts index 9f5e68c..afd9783 100644 --- a/app/web/src/helpers/hooks/useIdeState.ts +++ b/app/web/src/helpers/hooks/useIdeState.ts @@ -43,13 +43,14 @@ result = (cq.Workplane().circle(diam).extrude(20.0) show_object(result) `, jscad: ` + const { booleans, colors, primitives } = require('@jscad/modeling') // modeling comes from the included MODELING library const { intersect, subtract } = booleans const { colorize } = colors const { cube, cuboid, line, sphere, star } = primitives -const main = ({scale=1}) => { +const main = ({length=1}) => { const logo = [ colorize([1.0, 0.4, 1.0], subtract( cube({ size: 300 }), @@ -61,13 +62,18 @@ const main = ({scale=1}) => { )) ] - const transpCube = colorize([1, 0, 0, 0.75], cuboid({ size: [100 * scale, 100, 210 + (200 * scale)] })) + const transpCube = colorize([1, 0, 0, 0.75], cuboid({ size: [100, 100, length] })) const star2D = star({ vertices: 8, innerRadius: 150, outerRadius: 200 }) const line2D = colorize([1.0, 0, 0], line([[220, 220], [-220, 220], [-220, -220], [220, -220], [220, 220]])) return [transpCube, star2D, line2D, ...logo] } -module.exports = {main} +const getParameterDefinitions = ()=>{ + return [ + {type:'slider', name:'length', initial:210, caption:'Length', min:210, max:1500} + ] +} +module.exports = {main, getParameterDefinitions} `, } @@ -90,6 +96,7 @@ export interface State { data: any quality: 'low' | 'high' customizerParams?: any + lastParameters?: any } layout: any camera: { @@ -155,6 +162,7 @@ export const useIdeState = (): [State, (actionOrThunk: any) => any] => { type: payload.objectData?.type, data: payload.objectData?.data, customizerParams: payload.customizerParams, + lastParameters: payload.lastParameters, }, consoleMessages: payload.message ? [...state.consoleMessages, payload.message] @@ -219,6 +227,7 @@ export const useIdeState = (): [State, (actionOrThunk: any) => any] => { interface RequestRenderArgs { state: State dispatch: any + parameters: any, code: State['code'] camera: State['camera'] viewerSize: State['viewerSize'] @@ -234,6 +243,7 @@ export const requestRender = ({ viewerSize, quality = 'low', specialCadProcess = null, + parameters, }: RequestRenderArgs) => { if ( state.ideType !== 'INIT' && @@ -244,13 +254,14 @@ export const requestRender = ({ : cadPackages[state.ideType].render return renderFn({ code, + parameters, settings: { camera, viewerSize, quality, }, }) - .then(({ objectData, message, status, customizerParams }) => { + .then(({ objectData, message, status, customizerParams, lastParameters }) => { if (status === 'error') { dispatch({ type: 'errorRender', @@ -264,6 +275,7 @@ export const requestRender = ({ message, lastRunCode: code, customizerParams, + lastParameters, }, }) return objectData From 2b2080c232c4a771e8492e6cb4ddfd0d28555f5e Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Wed, 4 Aug 2021 00:11:55 +0200 Subject: [PATCH 04/19] more param types to check and style --- .../src/helpers/cadPackages/jscadParams.js | 14 +-- app/web/src/helpers/hooks/useIdeState.ts | 21 ++++- app/web/src/index.css | 88 +++++++++++++++++++ 3 files changed, 116 insertions(+), 7 deletions(-) diff --git a/app/web/src/helpers/cadPackages/jscadParams.js b/app/web/src/helpers/cadPackages/jscadParams.js index c72e80d..492c46d 100644 --- a/app/web/src/helpers/cadPackages/jscadParams.js +++ b/app/web/src/helpers/cadPackages/jscadParams.js @@ -1,4 +1,4 @@ -const GROUP_SELECTOR = 'DIV[type="group"] LABEL' +const GROUP_SELECTOR = 'DIV[type="group"]' const INPUT_SELECTOR = 'INPUT, SELECT' function forEachInput(target, callback){ @@ -15,7 +15,7 @@ function applyRange(inp){ let label = inp.previousElementSibling if(label.tagName == 'LABEL'){ let info = label.querySelector('I') - if(info) info.innerHTML = '('+inp.value+')' + if(info) info.innerHTML = inp.value } } @@ -88,13 +88,15 @@ export function genParams(defs, target, storedParams={}, callback=undefined, but } def.closed = closed - html +=`
` + html +=`
` html += `` if(type == 'checkbox') html += funcs[type](def) - html += `${caption}` + html += `${caption}${def.value}` if(funcs[type] && type != 'checkbox') html += funcs[type](def) @@ -141,7 +143,7 @@ export function genParams(defs, target, storedParams={}, callback=undefined, but callback(getParams(target),true) } - forEachGroup(target, label=>label.onclick=groupClick) + forEachGroup(target, div=>div.onclick=groupClick) } export function getParams(target){ @@ -150,7 +152,7 @@ export function getParams(target){ forEachGroup(target,elem=>{ let name = elem.getAttribute('name') - params[name] = (groupDiv.getAttribute('closed') == '1') ? 'closed':'' + params[name] = (elem.getAttribute('closed') == '1') ? 'closed':'' }) forEachInput(target,elem=>{ diff --git a/app/web/src/helpers/hooks/useIdeState.ts b/app/web/src/helpers/hooks/useIdeState.ts index afd9783..5ad4dd9 100644 --- a/app/web/src/helpers/hooks/useIdeState.ts +++ b/app/web/src/helpers/hooks/useIdeState.ts @@ -70,7 +70,26 @@ const main = ({length=1}) => { } const getParameterDefinitions = ()=>{ return [ - {type:'slider', name:'length', initial:210, caption:'Length', min:210, max:1500} + {type:'slider', name:'length', initial:210, caption:'Length', min:210, max:1500}, + { name: 'group1', type: 'group', caption: 'Group 1: Text Entry' }, + { name: 'text', type: 'text', initial: '', size: 20, maxLength: 20, caption: 'Plain Text:', placeholder: '20 characters' }, + { name: 'int', type: 'int', initial: 20, min: 1, max: 100, step: 1, caption: 'Integer:' }, + { name: 'number', type: 'number', initial: 2.0, min: 1.0, max: 10.0, step: 0.1, caption: 'Number:' }, + { name: 'date', type: 'date', initial: '2020-01-01', min: '2020-01-01', max: '2030-12-31', caption: 'Date:', placeholder: 'YYYY-MM-DD' }, + { name: 'email', type: 'email', initial: 'me@example.com', caption: 'Email:' }, + { name: 'url', type: 'url', initial: 'www.example.com', size: 40, maxLength: 40, caption: 'Url:', placeholder: '40 characters' }, + { name: 'password', type: 'password', initial: '', caption: 'Password:' }, + + { name: 'group2', type: 'group', caption: 'Group 2: Interactive Controls' }, + { name: 'checkbox', type: 'checkbox', checked: true, initial: '20', caption: 'Checkbox:' }, + { name: 'color', type: 'color', initial: '#FFB431', caption: 'Color:' }, + { name: 'slider', type: 'slider', initial: 3, min: 1, max: 10, step: 1, caption: 'Slider:' }, + { name: 'choice1', type: 'choice', caption: 'Dropdown Menu:', values: [0, 1, 2, 3], captions: ['No', 'Yes', 'Maybe', 'So so'], initial: 2 }, + { name: 'choice3', type: 'choice', caption: 'Dropdown Menu:', values: ['No', 'Yes', 'Maybe', 'So so'], initial: 'No' }, + { name: 'choice2', type: 'radio', caption: 'Radio Buttons:', values:[0, 1, 2, 3], captions: ['No', 'Yes', 'Maybe', 'So so'], initial: 5 }, + + { name: 'group3', type: 'group', initial: 'closed', caption: 'Group 3: Initially Closed Group' }, + { name: 'checkbox2', type: 'checkbox', checked: true, initial: '20', caption: 'Optional Checkbox:' }, ] } module.exports = {main, getParameterDefinitions} diff --git a/app/web/src/index.css b/app/web/src/index.css index 66183b1..c011ffd 100644 --- a/app/web/src/index.css +++ b/app/web/src/index.css @@ -115,3 +115,91 @@ input.error, textarea.error { border: 1px solid red; } +#jscad-customizer-block { + padding-bottom: 60px; /* hack because it gets cut off at the bottom for some reason*/ +} +#jscad-customizer-block > .form-line{ + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 5px 15px; + position: relative; +} +#jscad-customizer-block > .form-line:hover{ + background: rgba(0,0,0,0.3); +} + +#jscad-customizer-block > .form-line[type="group"]{ + background: rgba(255, 255, 255, 0.15); + padding-left: 50px; + padding-bottom: 12px; + cursor: pointer; +} +#jscad-customizer-block > .form-line[type="group"] > label{ + cursor: pointer; +} +#jscad-customizer-block > .form-line[closed="1"]:not([type="group"]){ + display: none; +} + +#jscad-customizer-block > .form-line[type="group"]:before { + position: absolute; + content: ">"; + left: 18px; + top: 13px; + font-size: 30px; + transform: rotate(90deg); + font-family: monospace; + +} +#jscad-customizer-block > .form-line[type="group"][closed="1"]:before { + transform: rotate(0deg); +} + +#jscad-customizer-block > .form-line select, +#jscad-customizer-block > .form-line input[type="text"], +#jscad-customizer-block > .form-line input[type="range"], +#jscad-customizer-block > .form-line input[type="slider"], +#jscad-customizer-block > .form-line input[type="number"], +#jscad-customizer-block > .form-line input[type="int"], +#jscad-customizer-block > .form-line input[type="date"], +#jscad-customizer-block > .form-line input[type="email"], +#jscad-customizer-block > .form-line input[type="url"], +#jscad-customizer-block > .form-line input[type="password"] +{ + background: rgba(73, 73, 73, 0.65); + border: 1px solid #FFFFFF; + width: 50%; + padding: 2px 8px; +} + +#jscad-customizer-block > .form-line label i{ + display: none; + font-style: normal; +} + +#jscad-customizer-block > .form-line[type="range"] label i, +#jscad-customizer-block > .form-line[type="slider"] label i, +#jscad-customizer-block > .form-line[type="color"] label i{ + display: inline-block; +} + +#jscad-customizer-block > .form-line input[type="range"]{ + position: relative; + top: 6px; +} +#jscad-customizer-block > .form-line > label > i{ + position: absolute; + top: 2px; + left: 70%; +} + +#jscad-customizer-block .form-line label{ + font-family: Fira Sans; + font-style: normal; + font-weight: bold; + font-size: 12px; + line-height: 14px; + + color: #CFCFD8; +} \ No newline at end of file From c9e3d3a708f7a1fe9d36e08c2cec5ddf1e6aa295 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Thu, 5 Aug 2021 07:44:21 +1000 Subject: [PATCH 05/19] Add live update checkbox to customizer --- .../src/components/Customizer/Customizer.tsx | 31 ++++++++++++------- .../helpers/cadPackages/jsCadController.ts | 5 ++- app/web/src/helpers/hooks/useIdeState.ts | 2 +- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/app/web/src/components/Customizer/Customizer.tsx b/app/web/src/components/Customizer/Customizer.tsx index 513220d..866c602 100644 --- a/app/web/src/components/Customizer/Customizer.tsx +++ b/app/web/src/components/Customizer/Customizer.tsx @@ -4,6 +4,7 @@ import { genParams, getParams } from 'src/helpers/cadPackages/jscadParams' const Customizer = () => { const [open, setOpen] = React.useState(true) + const [checked, setChecked] = React.useState(false) const ref = React.useRef() const jsCadCustomizerElement = ref.current const { state } = useIdeContext() @@ -13,13 +14,12 @@ const Customizer = () => { const handleRender2 = ()=>handleRender(getParams(ref.current)) React.useEffect(() => { - console.log({ jsCadCustomizerElement, customizerParams, lastParameters }) - if (jsCadCustomizerElement && customizerParams) { - genParams(customizerParams, jsCadCustomizerElement, lastParameters || {}, (values)=>{ - handleRender(values) - },[]) + if ((jsCadCustomizerElement && customizerParams)) { + genParams(customizerParams, jsCadCustomizerElement, lastParameters || {}, checked ? (values)=>{ + handleRender(values)}: () => {} + ,[]) } - }, [jsCadCustomizerElement, customizerParams, lastParameters]) + }, [jsCadCustomizerElement, customizerParams, lastParameters, checked]) return (
{
Parameters
- +
+ { + const newValue = !checked + if (newValue) handleRender2() + setChecked(newValue)}}/> + +
+
diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index 6178899..4724d78 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -103,8 +103,7 @@ export const render: DefaultKernelExport['render'] = async ({ let parameterDefinitions = [] scriptWorker.addEventListener('message', (e) => { const data = e.data - if (data.action == 'parameterDefinitions') { - console.log('message',data) + if (data.action == 'parameterDefinitions') { parameterDefinitions = data.data } else if (data.action == 'entities') { if (data.error) { @@ -123,7 +122,7 @@ export const render: DefaultKernelExport['render'] = async ({ callResolve() } }) - + callResolve() response = null scriptWorker.postMessage({ action: 'init', baseURI, alias: [] }) diff --git a/app/web/src/helpers/hooks/useIdeState.ts b/app/web/src/helpers/hooks/useIdeState.ts index 5ad4dd9..5ce9b7c 100644 --- a/app/web/src/helpers/hooks/useIdeState.ts +++ b/app/web/src/helpers/hooks/useIdeState.ts @@ -180,7 +180,7 @@ export const useIdeState = (): [State, (actionOrThunk: any) => any] => { ...state.objectData, type: payload.objectData?.type, data: payload.objectData?.data, - customizerParams: payload.customizerParams, + customizerParams: payload.customizerParams || state.objectData.customizerParams, lastParameters: payload.lastParameters, }, consoleMessages: payload.message From 00c0ae801abfe093d5c43577a5cec257508ca998 Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Wed, 4 Aug 2021 23:54:45 +0200 Subject: [PATCH 06/19] ... --- .../src/components/Customizer/Customizer.tsx | 7 ++- .../src/helpers/cadPackages/jscadParams.js | 60 ++++++++++++------- app/web/src/index.css | 15 +++-- 3 files changed, 56 insertions(+), 26 deletions(-) diff --git a/app/web/src/components/Customizer/Customizer.tsx b/app/web/src/components/Customizer/Customizer.tsx index 513220d..9cdf431 100644 --- a/app/web/src/components/Customizer/Customizer.tsx +++ b/app/web/src/components/Customizer/Customizer.tsx @@ -15,7 +15,12 @@ const Customizer = () => { React.useEffect(() => { console.log({ jsCadCustomizerElement, customizerParams, lastParameters }) if (jsCadCustomizerElement && customizerParams) { - genParams(customizerParams, jsCadCustomizerElement, lastParameters || {}, (values)=>{ + genParams(customizerParams, jsCadCustomizerElement, lastParameters || {}, (values, source)=>{ + console.log('change source', source) + if(source === 'group'){ + // save to local storage but do not render + return + } handleRender(values) },[]) } diff --git a/app/web/src/helpers/cadPackages/jscadParams.js b/app/web/src/helpers/cadPackages/jscadParams.js index 492c46d..c549bb2 100644 --- a/app/web/src/helpers/cadPackages/jscadParams.js +++ b/app/web/src/helpers/cadPackages/jscadParams.js @@ -13,7 +13,7 @@ const numeric = {number:1, float:1, int:1, range:1, slider:1} function applyRange(inp){ let label = inp.previousElementSibling - if(label.tagName == 'LABEL'){ + if(label && label.tagName == 'LABEL'){ let info = label.querySelector('I') if(info) info.innerHTML = inp.value } @@ -25,17 +25,8 @@ export function genParams(defs, target, storedParams={}, callback=undefined, but group:function({name,type, caption, captions, value, min,max}){ return '' }, - choice:function({name,type, caption, captions, value, values, min, max}){ - if(!captions) captions = values - - let ret = `' - }, + choice:inputChoice, + radio:inputRadio, float: inputNumber, range: inputNumber, slider: inputNumber, @@ -53,9 +44,33 @@ export function genParams(defs, target, storedParams={}, callback=undefined, but }, number: inputNumber, } + + function inputRadio({name, type, captions, value, values}){ + if(!captions) captions = values + + let ret = '
' + + for(let i =0; i${captions[i]}` + } + return ret +'
' + } + function inputChoice({name, type, captions, value, values}){ + if(!captions) captions = values + + let ret = `' + } + function inputNumber(def){ - let {name,type, caption, captions, value, min,max, step, placeholder, live} = def + let {name,type, value, min,max, step, placeholder, live} = def if(value === null || value === undefined) value = numeric[type] ? 0:''; let inputType = type if(type == 'int' || type=='float') inputType = 'number' @@ -88,7 +103,7 @@ export function genParams(defs, target, storedParams={}, callback=undefined, but } def.closed = closed - html +=`
` @@ -108,8 +123,8 @@ export function genParams(defs, target, storedParams={}, callback=undefined, but let missingKeys = Object.keys(missing) if(missingKeys.length) console.log('missing param impl',missingKeys); - function _callback(saveOnly){ - if(callback) callback(getParams(target)) + function _callback(source='change'){ + if(callback) callback(getParams(target), source) } html +='
' @@ -126,24 +141,27 @@ export function genParams(defs, target, storedParams={}, callback=undefined, but let type = inp.type inp.addEventListener('input', function(evt){ applyRange(inp) - if(inp.getAttribute('live') == '1') _callback(); + if(inp.getAttribute('live') === '1') _callback('live'); }) - if(inp.getAttribute('live') != '1') inp.addEventListener('change', _callback) + if(inp.getAttribute('live') !== '1') inp.addEventListener('change', _callback) }) function groupClick(evt){ - var groupDiv = evt.target.parentNode + var groupDiv = evt.target + if(groupDiv.tagName === 'LABEL') groupDiv = groupDiv.parentNode var closed = (groupDiv.getAttribute('closed') == '1') ? '0':'1' var name = evt.target.getAttribute('name') do{ groupDiv.setAttribute('closed', closed) groupDiv = groupDiv.nextElementSibling }while(groupDiv && groupDiv.getAttribute('type') != 'group') - callback(getParams(target),true) + _callback('group') } - forEachGroup(target, div=>div.onclick=groupClick) + forEachGroup(target, div=>{ + div.onclick=groupClick + }) } export function getParams(target){ diff --git a/app/web/src/index.css b/app/web/src/index.css index c011ffd..6b71da4 100644 --- a/app/web/src/index.css +++ b/app/web/src/index.css @@ -172,15 +172,22 @@ input.error, textarea.error { width: 50%; padding: 2px 8px; } +#jscad-customizer-block > .form-line > div{ + width: 50%; +} +#jscad-customizer-block > .form-line > div[type="radio"] > label{ + display: inline-block; + margin-left: 10px; +} -#jscad-customizer-block > .form-line label i{ +#jscad-customizer-block > .form-line > label i{ display: none; font-style: normal; } -#jscad-customizer-block > .form-line[type="range"] label i, -#jscad-customizer-block > .form-line[type="slider"] label i, -#jscad-customizer-block > .form-line[type="color"] label i{ +#jscad-customizer-block > .form-line[type="range"] > label i, +#jscad-customizer-block > .form-line[type="slider"] > label i, +#jscad-customizer-block > .form-line[type="color"] > label i{ display: inline-block; } From e851593c123d24169d533a2bbd92b846fe550d31 Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Fri, 6 Aug 2021 11:22:09 +0200 Subject: [PATCH 07/19] cleanup, few fixes --- app/web/src/components/Customizer/Customizer.tsx | 1 - app/web/src/helpers/cadPackages/jsCadController.ts | 1 - app/web/src/helpers/cadPackages/jscadParams.js | 7 +++++-- app/web/src/helpers/hooks/useIdeState.ts | 2 +- app/web/src/index.css | 4 ++++ 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/web/src/components/Customizer/Customizer.tsx b/app/web/src/components/Customizer/Customizer.tsx index c758e5b..597e3aa 100644 --- a/app/web/src/components/Customizer/Customizer.tsx +++ b/app/web/src/components/Customizer/Customizer.tsx @@ -14,7 +14,6 @@ const Customizer = () => { const handleRender2 = ()=>handleRender(getParams(ref.current)) React.useEffect(() => { - console.log({ jsCadCustomizerElement, customizerParams, lastParameters }) if (jsCadCustomizerElement && customizerParams) { genParams(customizerParams, jsCadCustomizerElement, lastParameters || {}, (values, source)=>{ if(source === 'group'){ diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index 4724d78..5be10d1 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -109,7 +109,6 @@ export const render: DefaultKernelExport['render'] = async ({ if (data.error) { response = createUnhealthyResponse(new Date(), data.error) } else { - console.log('lastParameters',lastParameters) response = createHealthyResponse({ type: 'geometry', data: [...data.entities.map(CSG2Object3D).filter((o) => o)], diff --git a/app/web/src/helpers/cadPackages/jscadParams.js b/app/web/src/helpers/cadPackages/jscadParams.js index c549bb2..bd1e23a 100644 --- a/app/web/src/helpers/cadPackages/jscadParams.js +++ b/app/web/src/helpers/cadPackages/jscadParams.js @@ -51,7 +51,7 @@ export function genParams(defs, target, storedParams={}, callback=undefined, but let ret = '
' for(let i =0; i${captions[i]}` } return ret +'
' @@ -182,7 +182,10 @@ export function getParams(target){ } if(numeric[elem.getAttribute('type')] || elem.getAttribute('numeric') == '1') value = parseFloat(value || 0) - params[name] = value + + if(elem.type == 'radio' && !elem.checked) return // skip if not checked radio button + + params[name] = value }) return params; } diff --git a/app/web/src/helpers/hooks/useIdeState.ts b/app/web/src/helpers/hooks/useIdeState.ts index 5ce9b7c..32304da 100644 --- a/app/web/src/helpers/hooks/useIdeState.ts +++ b/app/web/src/helpers/hooks/useIdeState.ts @@ -86,7 +86,7 @@ const getParameterDefinitions = ()=>{ { name: 'slider', type: 'slider', initial: 3, min: 1, max: 10, step: 1, caption: 'Slider:' }, { name: 'choice1', type: 'choice', caption: 'Dropdown Menu:', values: [0, 1, 2, 3], captions: ['No', 'Yes', 'Maybe', 'So so'], initial: 2 }, { name: 'choice3', type: 'choice', caption: 'Dropdown Menu:', values: ['No', 'Yes', 'Maybe', 'So so'], initial: 'No' }, - { name: 'choice2', type: 'radio', caption: 'Radio Buttons:', values:[0, 1, 2, 3], captions: ['No', 'Yes', 'Maybe', 'So so'], initial: 5 }, + { name: 'choice2', type: 'radio', caption: 'Radio Buttons:', values:[0, 1, 2, 3], captions: ['No', 'Yes', 'Maybe', 'So so'], initial: 2 }, { name: 'group3', type: 'group', initial: 'closed', caption: 'Group 3: Initially Closed Group' }, { name: 'checkbox2', type: 'checkbox', checked: true, initial: '20', caption: 'Optional Checkbox:' }, diff --git a/app/web/src/index.css b/app/web/src/index.css index 6b71da4..7d3b8c9 100644 --- a/app/web/src/index.css +++ b/app/web/src/index.css @@ -179,6 +179,10 @@ input.error, textarea.error { display: inline-block; margin-left: 10px; } +#jscad-customizer-block > .form-line[type="checkbox"] > label > input{ + position: absolute; + right: 14px; +} #jscad-customizer-block > .form-line > label i{ display: none; From e856f8208e4e4863f93644983c674f858dfb52ec Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Fri, 6 Aug 2021 11:26:00 +0200 Subject: [PATCH 08/19] Update useIdeState.ts --- app/web/src/helpers/hooks/useIdeState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/web/src/helpers/hooks/useIdeState.ts b/app/web/src/helpers/hooks/useIdeState.ts index 32304da..5f6cc21 100644 --- a/app/web/src/helpers/hooks/useIdeState.ts +++ b/app/web/src/helpers/hooks/useIdeState.ts @@ -70,7 +70,7 @@ const main = ({length=1}) => { } const getParameterDefinitions = ()=>{ return [ - {type:'slider', name:'length', initial:210, caption:'Length', min:210, max:1500}, + {type:'slider', name:'length', initial:340, caption:'Length', min:210, max:1500}, { name: 'group1', type: 'group', caption: 'Group 1: Text Entry' }, { name: 'text', type: 'text', initial: '', size: 20, maxLength: 20, caption: 'Plain Text:', placeholder: '20 characters' }, { name: 'int', type: 'int', initial: 20, min: 1, max: 100, step: 1, caption: 'Integer:' }, From 725e877f1bf5b27f227b6532b889888c33481a77 Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Fri, 6 Aug 2021 11:26:44 +0200 Subject: [PATCH 09/19] Update useIdeState.ts --- app/web/src/helpers/hooks/useIdeState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/web/src/helpers/hooks/useIdeState.ts b/app/web/src/helpers/hooks/useIdeState.ts index 5f6cc21..d4f5200 100644 --- a/app/web/src/helpers/hooks/useIdeState.ts +++ b/app/web/src/helpers/hooks/useIdeState.ts @@ -50,7 +50,7 @@ const { intersect, subtract } = booleans const { colorize } = colors const { cube, cuboid, line, sphere, star } = primitives -const main = ({length=1}) => { +const main = ({length=340}) => { const logo = [ colorize([1.0, 0.4, 1.0], subtract( cube({ size: 300 }), From 7cc989014a6913f8b986323a09c53b8523e35d80 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Fri, 6 Aug 2021 20:17:55 +1000 Subject: [PATCH 10/19] format project --- .../src/components/Customizer/Customizer.tsx | 43 ++- app/web/src/helpers/cadPackages/common.ts | 4 +- .../helpers/cadPackages/jsCadController.ts | 10 +- .../src/helpers/cadPackages/jscadParams.js | 343 ++++++++++-------- app/web/src/helpers/hooks/useIdeState.ts | 45 +-- 5 files changed, 242 insertions(+), 203 deletions(-) diff --git a/app/web/src/components/Customizer/Customizer.tsx b/app/web/src/components/Customizer/Customizer.tsx index 597e3aa..dca4b1c 100644 --- a/app/web/src/components/Customizer/Customizer.tsx +++ b/app/web/src/components/Customizer/Customizer.tsx @@ -1,6 +1,6 @@ -import { useRender, } from 'src/components/IdeWrapper/useRender' +import { useRender } from 'src/components/IdeWrapper/useRender' import { useIdeContext } from 'src/helpers/hooks/useIdeContext' -import { genParams, getParams } from 'src/helpers/cadPackages/jscadParams' +import { genParams, getParams } from 'src/helpers/cadPackages/jscadParams' const Customizer = () => { const [open, setOpen] = React.useState(true) @@ -11,17 +11,23 @@ const Customizer = () => { const customizerParams = state?.objectData?.customizerParams const lastParameters = state?.objectData?.lastParameters const handleRender = useRender() - const handleRender2 = ()=>handleRender(getParams(ref.current)) + const handleRender2 = () => handleRender(getParams(ref.current)) React.useEffect(() => { if (jsCadCustomizerElement && customizerParams) { - genParams(customizerParams, jsCadCustomizerElement, lastParameters || {}, (values, source)=>{ - if(source === 'group'){ - // save to local storage but do not render - return - } - if(checked) handleRender(values) - },[]) + genParams( + customizerParams, + jsCadCustomizerElement, + lastParameters || {}, + (values, source) => { + if (source === 'group') { + // save to local storage but do not render + return + } + if (checked) handleRender(values) + }, + [] + ) } }, [jsCadCustomizerElement, customizerParams, lastParameters, checked]) return ( @@ -37,11 +43,17 @@ const Customizer = () => {
Parameters
-
- { - const newValue = !checked - if (newValue) handleRender2() - setChecked(newValue)}}/> +
+ { + const newValue = !checked + if (newValue) handleRender2() + setChecked(newValue) + }} + />
-
diff --git a/app/web/src/helpers/cadPackages/common.ts b/app/web/src/helpers/cadPackages/common.ts index 5dab46d..4bdec2a 100644 --- a/app/web/src/helpers/cadPackages/common.ts +++ b/app/web/src/helpers/cadPackages/common.ts @@ -12,7 +12,7 @@ export const stlToGeometry = (url) => export interface RenderArgs { code: State['code'] - parameters: any, + parameters: any settings: { camera: State['camera'] viewerSize: State['viewerSize'] @@ -42,7 +42,7 @@ export function createHealthyResponse({ type, customizerParams, lastParameters, - }: { +}: { date: Date data: any consoleMessage: string diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index 5be10d1..b0c4ddc 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -86,7 +86,9 @@ export const render: DefaultKernelExport['render'] = async ({ settings, }: RenderArgs) => { if (!scriptWorker) { - console.trace('************************** creating new worker ************************') + console.trace( + '************************** creating new worker ************************' + ) const baseURI = document.baseURI.toString() const script = `let baseURI = '${baseURI}' importScripts(new URL('${scriptUrl}',baseURI)) @@ -127,14 +129,14 @@ export const render: DefaultKernelExport['render'] = async ({ scriptWorker.postMessage({ action: 'init', baseURI, alias: [] }) } - if(parameters){ + if (parameters) { // we are not evaluating code, but reacting to parameters change scriptWorker.postMessage({ action: 'updateParams', worker: 'script', params: parameters, }) - }else{ + } else { scriptWorker.postMessage({ action: 'runScript', worker: 'script', @@ -154,7 +156,7 @@ export const render: DefaultKernelExport['render'] = async ({ await waitResult resolveReference = null - if(parameters) delete response.customizerParams + if (parameters) delete response.customizerParams return response } diff --git a/app/web/src/helpers/cadPackages/jscadParams.js b/app/web/src/helpers/cadPackages/jscadParams.js index bd1e23a..66e6527 100644 --- a/app/web/src/helpers/cadPackages/jscadParams.js +++ b/app/web/src/helpers/cadPackages/jscadParams.js @@ -1,192 +1,215 @@ const GROUP_SELECTOR = 'DIV[type="group"]' const INPUT_SELECTOR = 'INPUT, SELECT' -function forEachInput(target, callback){ - target.querySelectorAll(INPUT_SELECTOR).forEach(callback) +function forEachInput(target, callback) { + target.querySelectorAll(INPUT_SELECTOR).forEach(callback) } -function forEachGroup(target, callback){ - target.querySelectorAll(GROUP_SELECTOR).forEach(callback) +function forEachGroup(target, callback) { + target.querySelectorAll(GROUP_SELECTOR).forEach(callback) } -const numeric = {number:1, float:1, int:1, range:1, slider:1} +const numeric = { number: 1, float: 1, int: 1, range: 1, slider: 1 } -function applyRange(inp){ - let label = inp.previousElementSibling - if(label && label.tagName == 'LABEL'){ - let info = label.querySelector('I') - if(info) info.innerHTML = inp.value +function applyRange(inp) { + let label = inp.previousElementSibling + if (label && label.tagName == 'LABEL') { + let info = label.querySelector('I') + if (info) info.innerHTML = inp.value + } +} + +export function genParams( + defs, + target, + storedParams = {}, + callback = undefined, + buttons = ['reset', 'save', 'load', 'edit', 'link'] +) { + let funcs = { + group: function ({ name, type, caption, captions, value, min, max }) { + return '' + }, + choice: inputChoice, + radio: inputRadio, + float: inputNumber, + range: inputNumber, + slider: inputNumber, + int: inputNumber, + text: inputNumber, + url: inputNumber, + email: inputNumber, + date: inputNumber, + password: inputNumber, + color: inputNumber, + // TODO radio similar options as choice + checkbox: function ({ + name, + type, + caption, + captions, + value, + checked, + min, + max, + }) { + let checkedStr = value === 'checked' || value === true ? 'checked' : '' + return `` + }, + number: inputNumber, + } + + function inputRadio({ name, type, captions, value, values }) { + if (!captions) captions = values + + let ret = '
' + + for (let i = 0; i < values.length; i++) { + let checked = value == values[i] || value == captions[i] ? 'checked' : '' + ret += `` } -} + return ret + '
' + } -export function genParams(defs, target, storedParams={}, callback=undefined, buttons=['reset','save','load','edit','link']){ + function inputChoice({ name, type, captions, value, values }) { + if (!captions) captions = values - let funcs = { - group:function({name,type, caption, captions, value, min,max}){ - return '' - }, - choice:inputChoice, - radio:inputRadio, - float: inputNumber, - range: inputNumber, - slider: inputNumber, - int: inputNumber, - text: inputNumber, - url: inputNumber, - email: inputNumber, - date: inputNumber, - password: inputNumber, - color: inputNumber, - // TODO radio similar options as choice - checkbox :function({name,type, caption, captions, value, checked, min,max}){ - let checkedStr = (value === 'checked' || value === true) ? 'checked':'' - return `` - }, - number: inputNumber, - } + let ret = `' + } - let ret = '
' + function inputNumber(def) { + let { name, type, value, min, max, step, placeholder, live } = def + if (value === null || value === undefined) value = numeric[type] ? 0 : '' + let inputType = type + if (type == 'int' || type == 'float') inputType = 'number' + if (type == 'range' || type == 'slider') inputType = 'range' + var str = `' + } - for(let i =0; i${captions[i]}` - } - return ret +'
' - } - - function inputChoice({name, type, captions, value, values}){ - if(!captions) captions = values + let html = '' + let closed = false + let missing = {} - let ret = `' - } + if (storedParams[name] !== undefined) { + def.value = storedParams[name] + } else { + def.value = def.initial || def['default'] || def.checked + } - function inputNumber(def){ - let {name,type, value, min,max, step, placeholder, live} = def - if(value === null || value === undefined) value = numeric[type] ? 0:''; - let inputType = type - if(type == 'int' || type=='float') inputType = 'number' - if(type == 'range' || type=='slider') inputType = 'range' - var str = `'; - } + if (type == 'group') { + closed = def.value == 'closed' + } + def.closed = closed - let html = ''; - let closed = false - let missing = {} + html += `
` - defs.forEach(def=>{ - let {type, caption, name} = def + html += `` + if (type == 'checkbox') html += funcs[type](def) + html += `${caption}${def.value}` - if(storedParams[name] !== undefined){ - def.value = storedParams[name]; - }else { - def.value = def.initial || def['default'] || def.checked - } + if (funcs[type] && type != 'checkbox') html += funcs[type](def) - if(type == 'group'){ - closed = def.value == 'closed' - } - def.closed = closed - - html +=`
` - - html += `` - if(type == 'checkbox') html += funcs[type](def) - html += `${caption}${def.value}` - - if(funcs[type] && type != 'checkbox') html += funcs[type](def) + if (!funcs[type]) missing[type] = 1 - if(!funcs[type]) missing[type] = 1 - - html +='
\n' - }) + html += '
\n' + }) - let missingKeys = Object.keys(missing) - if(missingKeys.length) console.log('missing param impl',missingKeys); + let missingKeys = Object.keys(missing) + if (missingKeys.length) console.log('missing param impl', missingKeys) - function _callback(source='change'){ - if(callback) callback(getParams(target), source) - } + function _callback(source = 'change') { + if (callback) callback(getParams(target), source) + } - html +='
' - buttons.forEach(b=>{ - if(typeof b === 'string') b = {id:b, name:b} - let {id,name} = b - html += `` - }) - html += '
' + html += '
' + buttons.forEach((b) => { + if (typeof b === 'string') b = { id: b, name: b } + let { id, name } = b + html += `` + }) + html += '
' - target.innerHTML = html + target.innerHTML = html - forEachInput(target, inp=>{ - let type = inp.type - inp.addEventListener('input', function(evt){ - applyRange(inp) - if(inp.getAttribute('live') === '1') _callback('live'); - }) - if(inp.getAttribute('live') !== '1') inp.addEventListener('change', _callback) - - }) - - function groupClick(evt){ - var groupDiv = evt.target - if(groupDiv.tagName === 'LABEL') groupDiv = groupDiv.parentNode - var closed = (groupDiv.getAttribute('closed') == '1') ? '0':'1' - var name = evt.target.getAttribute('name') - do{ - groupDiv.setAttribute('closed', closed) - groupDiv = groupDiv.nextElementSibling - }while(groupDiv && groupDiv.getAttribute('type') != 'group') - _callback('group') - } - - forEachGroup(target, div=>{ - div.onclick=groupClick - }) -} - -export function getParams(target){ - let params = {} - if(!target) return params - - forEachGroup(target,elem=>{ - let name = elem.getAttribute('name') - params[name] = (elem.getAttribute('closed') == '1') ? 'closed':'' + forEachInput(target, (inp) => { + let type = inp.type + inp.addEventListener('input', function (evt) { + applyRange(inp) + if (inp.getAttribute('live') === '1') _callback('live') }) + if (inp.getAttribute('live') !== '1') + inp.addEventListener('change', _callback) + }) - forEachInput(target,elem=>{ - let name = elem.name - let value = elem.value - if(elem.tagName == 'INPUT'){ - if(elem.type == 'checkbox') value = elem.checked - if(elem.type == 'range' || elem.type == 'color') applyRange(elem) - } + function groupClick(evt) { + var groupDiv = evt.target + if (groupDiv.tagName === 'LABEL') groupDiv = groupDiv.parentNode + var closed = groupDiv.getAttribute('closed') == '1' ? '0' : '1' + var name = evt.target.getAttribute('name') + do { + groupDiv.setAttribute('closed', closed) + groupDiv = groupDiv.nextElementSibling + } while (groupDiv && groupDiv.getAttribute('type') != 'group') + _callback('group') + } - if(numeric[elem.getAttribute('type')] || elem.getAttribute('numeric') == '1') value = parseFloat(value || 0) - - if(elem.type == 'radio' && !elem.checked) return // skip if not checked radio button - - params[name] = value - }) - return params; + forEachGroup(target, (div) => { + div.onclick = groupClick + }) } +export function getParams(target) { + let params = {} + if (!target) return params + + forEachGroup(target, (elem) => { + let name = elem.getAttribute('name') + params[name] = elem.getAttribute('closed') == '1' ? 'closed' : '' + }) + + forEachInput(target, (elem) => { + let name = elem.name + let value = elem.value + if (elem.tagName == 'INPUT') { + if (elem.type == 'checkbox') value = elem.checked + if (elem.type == 'range' || elem.type == 'color') applyRange(elem) + } + + if ( + numeric[elem.getAttribute('type')] || + elem.getAttribute('numeric') == '1' + ) + value = parseFloat(value || 0) + + if (elem.type == 'radio' && !elem.checked) return // skip if not checked radio button + + params[name] = value + }) + return params +} diff --git a/app/web/src/helpers/hooks/useIdeState.ts b/app/web/src/helpers/hooks/useIdeState.ts index d4f5200..2de05d4 100644 --- a/app/web/src/helpers/hooks/useIdeState.ts +++ b/app/web/src/helpers/hooks/useIdeState.ts @@ -180,7 +180,8 @@ export const useIdeState = (): [State, (actionOrThunk: any) => any] => { ...state.objectData, type: payload.objectData?.type, data: payload.objectData?.data, - customizerParams: payload.customizerParams || state.objectData.customizerParams, + customizerParams: + payload.customizerParams || state.objectData.customizerParams, lastParameters: payload.lastParameters, }, consoleMessages: payload.message @@ -246,7 +247,7 @@ export const useIdeState = (): [State, (actionOrThunk: any) => any] => { interface RequestRenderArgs { state: State dispatch: any - parameters: any, + parameters: any code: State['code'] camera: State['camera'] viewerSize: State['viewerSize'] @@ -280,26 +281,28 @@ export const requestRender = ({ quality, }, }) - .then(({ objectData, message, status, customizerParams, lastParameters }) => { - if (status === 'error') { - dispatch({ - type: 'errorRender', - payload: { message }, - }) - } else { - dispatch({ - type: 'healthyRender', - payload: { - objectData, - message, - lastRunCode: code, - customizerParams, - lastParameters, - }, - }) - return objectData + .then( + ({ objectData, message, status, customizerParams, lastParameters }) => { + if (status === 'error') { + dispatch({ + type: 'errorRender', + payload: { message }, + }) + } else { + dispatch({ + type: 'healthyRender', + payload: { + objectData, + message, + lastRunCode: code, + customizerParams, + lastParameters, + }, + }) + return objectData + } } - }) + ) .catch(() => dispatch({ type: 'resetLoading' })) // TODO should probably display something to the user here } } From 53da1e49a006af34b495b099081a200cbaaa06a5 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Fri, 6 Aug 2021 20:26:21 +1000 Subject: [PATCH 11/19] Remove console logs --- app/web/public/demo-worker.js | 4 ---- app/web/src/components/Customizer/Customizer.tsx | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/web/public/demo-worker.js b/app/web/public/demo-worker.js index d8b18eb..10e086c 100644 --- a/app/web/public/demo-worker.js +++ b/app/web/public/demo-worker.js @@ -247,7 +247,6 @@ const makeScriptWorker = ({callback, convertToSolids})=>{ let time = Date.now() let solids let transfer = [] - console.log('run main') try{ solids = main(params) }catch(e){ @@ -487,7 +486,6 @@ let perspectiveCamera let time = Date.now() renderer(renderOptions) if(updateRender){ - console.log(updateRender, ' first render', Date.now()-time); updateRender = ''; } } @@ -550,7 +548,6 @@ return (params)=>{ workerBaseURI = baseURI const sendCmd = (params, transfer)=>{ - console.log('sendCmd', params.worker, params.action, params) if(params.worker === 'render') sendToRender(params, transfer) else if(params.worker === 'script') @@ -570,7 +567,6 @@ return (params)=>{ const makeRenderWorkerHere = (scope === 'main' && canvas && !renderInWorker) || (scope === 'worker' && render) // worker is in current thread if(makeRenderWorkerHere){ - console.log('render in scope: '+scope); renderWorker = makeRenderWorker({callback:sendCmd}) sendToRender = (params, transfer)=>renderWorker.postMessage(params, transfer) } diff --git a/app/web/src/components/Customizer/Customizer.tsx b/app/web/src/components/Customizer/Customizer.tsx index dca4b1c..47dda4b 100644 --- a/app/web/src/components/Customizer/Customizer.tsx +++ b/app/web/src/components/Customizer/Customizer.tsx @@ -20,11 +20,11 @@ const Customizer = () => { jsCadCustomizerElement, lastParameters || {}, (values, source) => { - if (source === 'group') { + if (source === 'group' || !checked) { // save to local storage but do not render return } - if (checked) handleRender(values) + handleRender(values) }, [] ) From f83d1b395f23fd8226e29adccc4b024be8fa9934 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sat, 7 Aug 2021 13:53:17 +1000 Subject: [PATCH 12/19] Fix param panel collapse issue --- .../src/components/Customizer/Customizer.tsx | 46 +++---------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/app/web/src/components/Customizer/Customizer.tsx b/app/web/src/components/Customizer/Customizer.tsx index 47dda4b..1767897 100644 --- a/app/web/src/components/Customizer/Customizer.tsx +++ b/app/web/src/components/Customizer/Customizer.tsx @@ -62,46 +62,12 @@ const Customizer = () => {
-
-
-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-

lots of lines should cause scroll

-
+
+
) From 2d7df96ad930fd59028e99ed1cf9dc4485da630f Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sat, 7 Aug 2021 15:29:17 +1000 Subject: [PATCH 13/19] Add a few type improvements to jscadParams.ts --- .../src/components/Customizer/Customizer.tsx | 2 +- .../src/components/IdeWrapper/useRender.ts | 3 +- app/web/src/helpers/cadPackages/common.ts | 4 + app/web/src/helpers/cadPackages/index.ts | 2 +- .../{ => jsCad}/jsCadController.ts | 2 +- .../{jscadParams.js => jsCad/jscadParams.ts} | 73 +++++++++---------- 6 files changed, 43 insertions(+), 43 deletions(-) rename app/web/src/helpers/cadPackages/{ => jsCad}/jsCadController.ts (99%) rename app/web/src/helpers/cadPackages/{jscadParams.js => jsCad/jscadParams.ts} (77%) diff --git a/app/web/src/components/Customizer/Customizer.tsx b/app/web/src/components/Customizer/Customizer.tsx index 1767897..37e8c1a 100644 --- a/app/web/src/components/Customizer/Customizer.tsx +++ b/app/web/src/components/Customizer/Customizer.tsx @@ -1,6 +1,6 @@ import { useRender } from 'src/components/IdeWrapper/useRender' import { useIdeContext } from 'src/helpers/hooks/useIdeContext' -import { genParams, getParams } from 'src/helpers/cadPackages/jscadParams' +import { genParams, getParams } from 'src/helpers/cadPackages/jsCad/jscadParams' const Customizer = () => { const [open, setOpen] = React.useState(true) diff --git a/app/web/src/components/IdeWrapper/useRender.ts b/app/web/src/components/IdeWrapper/useRender.ts index 52d233d..17824d6 100644 --- a/app/web/src/components/IdeWrapper/useRender.ts +++ b/app/web/src/components/IdeWrapper/useRender.ts @@ -1,9 +1,10 @@ import { makeCodeStoreKey, requestRender } from 'src/helpers/hooks/useIdeState' import { useIdeContext } from 'src/helpers/hooks/useIdeContext' +import type { RawCustomizerParams } from 'src/helpers/cadPackages/common' export const useRender = () => { const { state, thunkDispatch } = useIdeContext() - return (parameters) => { + return (parameters?: RawCustomizerParams) => { thunkDispatch((dispatch, getState) => { const state = getState() dispatch({ type: 'setLoading' }) diff --git a/app/web/src/helpers/cadPackages/common.ts b/app/web/src/helpers/cadPackages/common.ts index 4bdec2a..95a60c3 100644 --- a/app/web/src/helpers/cadPackages/common.ts +++ b/app/web/src/helpers/cadPackages/common.ts @@ -35,6 +35,10 @@ export interface HealthyResponse { lastParameters?: any } +export interface RawCustomizerParams { + [paramName: string]: number | string | boolean +} + export function createHealthyResponse({ date, data, diff --git a/app/web/src/helpers/cadPackages/index.ts b/app/web/src/helpers/cadPackages/index.ts index 145717e..568e9b9 100644 --- a/app/web/src/helpers/cadPackages/index.ts +++ b/app/web/src/helpers/cadPackages/index.ts @@ -3,7 +3,7 @@ import type { CadPackage } from 'src/helpers/hooks/useIdeState' import openscad from './openScadController' import cadquery from './cadQueryController' -import jscad from './jsCadController' +import jscad from './jsCad/jsCadController' export const cadPackages: { [key in CadPackage]: DefaultKernelExport } = { openscad, diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCad/jsCadController.ts similarity index 99% rename from app/web/src/helpers/cadPackages/jsCadController.ts rename to app/web/src/helpers/cadPackages/jsCad/jsCadController.ts index b0c4ddc..6cabb4a 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCad/jsCadController.ts @@ -3,7 +3,7 @@ import { DefaultKernelExport, createUnhealthyResponse, createHealthyResponse, -} from './common' +} from '../common' import { MeshPhongMaterial, LineBasicMaterial, diff --git a/app/web/src/helpers/cadPackages/jscadParams.js b/app/web/src/helpers/cadPackages/jsCad/jscadParams.ts similarity index 77% rename from app/web/src/helpers/cadPackages/jscadParams.js rename to app/web/src/helpers/cadPackages/jsCad/jscadParams.ts index 66e6527..b43911a 100644 --- a/app/web/src/helpers/cadPackages/jscadParams.js +++ b/app/web/src/helpers/cadPackages/jsCad/jscadParams.ts @@ -1,20 +1,25 @@ +import type { RawCustomizerParams } from '../common' + const GROUP_SELECTOR = 'DIV[type="group"]' const INPUT_SELECTOR = 'INPUT, SELECT' -function forEachInput(target, callback) { +function forEachInput( + target: HTMLElement, + callback: (e: HTMLInputElement) => void +) { target.querySelectorAll(INPUT_SELECTOR).forEach(callback) } -function forEachGroup(target, callback) { +function forEachGroup(target: HTMLElement, callback: (e: HTMLElement) => void) { target.querySelectorAll(GROUP_SELECTOR).forEach(callback) } const numeric = { number: 1, float: 1, int: 1, range: 1, slider: 1 } function applyRange(inp) { - let label = inp.previousElementSibling + const label = inp.previousElementSibling if (label && label.tagName == 'LABEL') { - let info = label.querySelector('I') + const info = label.querySelector('I') if (info) info.innerHTML = inp.value } } @@ -26,10 +31,8 @@ export function genParams( callback = undefined, buttons = ['reset', 'save', 'load', 'edit', 'link'] ) { - let funcs = { - group: function ({ name, type, caption, captions, value, min, max }) { - return '' - }, + const funcs = { + group: () => '', choice: inputChoice, radio: inputRadio, float: inputNumber, @@ -43,17 +46,8 @@ export function genParams( password: inputNumber, color: inputNumber, // TODO radio similar options as choice - checkbox: function ({ - name, - type, - caption, - captions, - value, - checked, - min, - max, - }) { - let checkedStr = value === 'checked' || value === true ? 'checked' : '' + checkbox: function ({ name, value }) { + const checkedStr = value === 'checked' || value === true ? 'checked' : '' return `` }, number: inputNumber, @@ -65,7 +59,8 @@ export function genParams( let ret = '
' for (let i = 0; i < values.length; i++) { - let checked = value == values[i] || value == captions[i] ? 'checked' : '' + const checked = + value == values[i] || value == captions[i] ? 'checked' : '' ret += `` @@ -81,7 +76,8 @@ export function genParams( }">` for (let i = 0; i < values.length; i++) { - let checked = value == values[i] || value == captions[i] ? 'selected' : '' + const checked = + value == values[i] || value == captions[i] ? 'selected' : '' ret += `` } return ret + '' @@ -93,7 +89,7 @@ export function genParams( let inputType = type if (type == 'int' || type == 'float') inputType = 'number' if (type == 'range' || type == 'slider') inputType = 'range' - var str = ` { - let { type, caption, name } = def + const { type, caption, name } = def if (storedParams[name] !== undefined) { def.value = storedParams[name] @@ -140,7 +136,7 @@ export function genParams( html += '
\n' }) - let missingKeys = Object.keys(missing) + const missingKeys = Object.keys(missing) if (missingKeys.length) console.log('missing param impl', missingKeys) function _callback(source = 'change') { @@ -148,9 +144,9 @@ export function genParams( } html += '
' - buttons.forEach((b) => { - if (typeof b === 'string') b = { id: b, name: b } - let { id, name } = b + buttons.forEach((button) => { + const { id, name } = + typeof button === 'string' ? { id: button, name: button } : button html += `` }) html += '
' @@ -158,7 +154,7 @@ export function genParams( target.innerHTML = html forEachInput(target, (inp) => { - let type = inp.type + const type = inp.type inp.addEventListener('input', function (evt) { applyRange(inp) if (inp.getAttribute('live') === '1') _callback('live') @@ -168,10 +164,9 @@ export function genParams( }) function groupClick(evt) { - var groupDiv = evt.target + let groupDiv = evt.target if (groupDiv.tagName === 'LABEL') groupDiv = groupDiv.parentNode - var closed = groupDiv.getAttribute('closed') == '1' ? '0' : '1' - var name = evt.target.getAttribute('name') + const closed = groupDiv.getAttribute('closed') == '1' ? '0' : '1' do { groupDiv.setAttribute('closed', closed) groupDiv = groupDiv.nextElementSibling @@ -184,20 +179,20 @@ export function genParams( }) } -export function getParams(target) { - let params = {} +export function getParams(target: HTMLElement): RawCustomizerParams { + const params = {} if (!target) return params forEachGroup(target, (elem) => { - let name = elem.getAttribute('name') + const name = elem.getAttribute('name') params[name] = elem.getAttribute('closed') == '1' ? 'closed' : '' }) forEachInput(target, (elem) => { - let name = elem.name - let value = elem.value + const name = elem.name + let value: RawCustomizerParams[string] = elem.value if (elem.tagName == 'INPUT') { - if (elem.type == 'checkbox') value = elem.checked + if (elem.type == 'checkbox') value = elem?.checked if (elem.type == 'range' || elem.type == 'color') applyRange(elem) } @@ -205,7 +200,7 @@ export function getParams(target) { numeric[elem.getAttribute('type')] || elem.getAttribute('numeric') == '1' ) - value = parseFloat(value || 0) + value = parseFloat(String(value || 0)) if (elem.type == 'radio' && !elem.checked) return // skip if not checked radio button From 02160e1e8eb52d604a6b387ef3ad4719253dac8f Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sat, 7 Aug 2021 17:00:29 +1000 Subject: [PATCH 14/19] store latest params in the store --- .../src/components/Customizer/Customizer.tsx | 26 +++++++++---------- .../src/components/IdeWrapper/useRender.ts | 5 ++-- app/web/src/helpers/cadPackages/common.ts | 10 +++---- .../cadPackages/jsCad/jsCadController.ts | 6 ++--- .../helpers/cadPackages/jsCad/jscadParams.ts | 6 ++--- app/web/src/helpers/hooks/useIdeState.ts | 25 +++++++++++++----- 6 files changed, 43 insertions(+), 35 deletions(-) diff --git a/app/web/src/components/Customizer/Customizer.tsx b/app/web/src/components/Customizer/Customizer.tsx index 37e8c1a..9010328 100644 --- a/app/web/src/components/Customizer/Customizer.tsx +++ b/app/web/src/components/Customizer/Customizer.tsx @@ -1,35 +1,33 @@ import { useRender } from 'src/components/IdeWrapper/useRender' import { useIdeContext } from 'src/helpers/hooks/useIdeContext' -import { genParams, getParams } from 'src/helpers/cadPackages/jsCad/jscadParams' +import { genParams } from 'src/helpers/cadPackages/jsCad/jscadParams' const Customizer = () => { const [open, setOpen] = React.useState(true) const [checked, setChecked] = React.useState(false) const ref = React.useRef() const jsCadCustomizerElement = ref.current - const { state } = useIdeContext() - const customizerParams = state?.objectData?.customizerParams - const lastParameters = state?.objectData?.lastParameters + const { state, thunkDispatch } = useIdeContext() + const customizerParams = state?.customizerParams + const currentParameters = state?.currentParameters const handleRender = useRender() - const handleRender2 = () => handleRender(getParams(ref.current)) React.useEffect(() => { if (jsCadCustomizerElement && customizerParams) { genParams( customizerParams, jsCadCustomizerElement, - lastParameters || {}, + currentParameters || {}, (values, source) => { - if (source === 'group' || !checked) { - // save to local storage but do not render - return + thunkDispatch({ type: 'setCurrentCustomizerParams', payload: values }) + if (checked) { + handleRender() } - handleRender(values) }, [] ) } - }, [jsCadCustomizerElement, customizerParams, lastParameters, checked]) + }, [jsCadCustomizerElement, customizerParams, currentParameters, checked]) return (
{ className="mr-6" type="checkbox" checked={checked} - onChange={({ target }) => { + onChange={() => { const newValue = !checked - if (newValue) handleRender2() + if (newValue) handleRender() setChecked(newValue) }} /> diff --git a/app/web/src/components/IdeWrapper/useRender.ts b/app/web/src/components/IdeWrapper/useRender.ts index 17824d6..4ac6312 100644 --- a/app/web/src/components/IdeWrapper/useRender.ts +++ b/app/web/src/components/IdeWrapper/useRender.ts @@ -1,10 +1,9 @@ import { makeCodeStoreKey, requestRender } from 'src/helpers/hooks/useIdeState' import { useIdeContext } from 'src/helpers/hooks/useIdeContext' -import type { RawCustomizerParams } from 'src/helpers/cadPackages/common' export const useRender = () => { const { state, thunkDispatch } = useIdeContext() - return (parameters?: RawCustomizerParams) => { + return () => { thunkDispatch((dispatch, getState) => { const state = getState() dispatch({ type: 'setLoading' }) @@ -14,7 +13,7 @@ export const useRender = () => { code: state.code, viewerSize: state.viewerSize, camera: state.camera, - parameters, + parameters: state.currentParameters, }) }) localStorage.setItem(makeCodeStoreKey(state.ideType), state.code) diff --git a/app/web/src/helpers/cadPackages/common.ts b/app/web/src/helpers/cadPackages/common.ts index 95a60c3..7c17760 100644 --- a/app/web/src/helpers/cadPackages/common.ts +++ b/app/web/src/helpers/cadPackages/common.ts @@ -31,8 +31,8 @@ export interface HealthyResponse { data: any type: 'stl' | 'png' | 'geometry' } - customizerParams?: any - lastParameters?: any + customizerParams?: any[] + currentParameters?: RawCustomizerParams } export interface RawCustomizerParams { @@ -45,14 +45,14 @@ export function createHealthyResponse({ consoleMessage, type, customizerParams, - lastParameters, + currentParameters, }: { date: Date data: any consoleMessage: string type: HealthyResponse['objectData']['type'] customizerParams?: any - lastParameters?: any + currentParameters?: any }): HealthyResponse { return { status: 'healthy', @@ -66,7 +66,7 @@ export function createHealthyResponse({ time: date, }, customizerParams, - lastParameters, + currentParameters, } } diff --git a/app/web/src/helpers/cadPackages/jsCad/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCad/jsCadController.ts index 6cabb4a..c40594d 100644 --- a/app/web/src/helpers/cadPackages/jsCad/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCad/jsCadController.ts @@ -70,7 +70,7 @@ function CSG2Object3D(obj) { } let scriptWorker -let lastParameters = {} +let currentParameters = {} const scriptUrl = '/demo-worker.js' let resolveReference = null let response = null @@ -117,7 +117,7 @@ export const render: DefaultKernelExport['render'] = async ({ consoleMessage: data.scriptStats, date: new Date(), customizerParams: parameterDefinitions, - lastParameters, + currentParameters, }) } callResolve() @@ -148,7 +148,7 @@ export const render: DefaultKernelExport['render'] = async ({ // we need this to keep the form filled with same data when new parameter definitions arrive // each render of the script could provide new paramaters. In case some of them are still rpesent // it is expected for them to stay the same and not just reset - lastParameters = parameters || {} + currentParameters = parameters || {} const waitResult = new Promise((resolve) => { resolveReference = resolve diff --git a/app/web/src/helpers/cadPackages/jsCad/jscadParams.ts b/app/web/src/helpers/cadPackages/jsCad/jscadParams.ts index b43911a..a397e45 100644 --- a/app/web/src/helpers/cadPackages/jsCad/jscadParams.ts +++ b/app/web/src/helpers/cadPackages/jsCad/jscadParams.ts @@ -28,7 +28,7 @@ export function genParams( defs, target, storedParams = {}, - callback = undefined, + callback: (values: RawCustomizerParams, source: any) => void = undefined, buttons = ['reset', 'save', 'load', 'edit', 'link'] ) { const funcs = { @@ -140,7 +140,7 @@ export function genParams( if (missingKeys.length) console.log('missing param impl', missingKeys) function _callback(source = 'change') { - if (callback) callback(getParams(target), source) + if (callback && source !== 'group') callback(getParams(target), source) } html += '
' @@ -179,7 +179,7 @@ export function genParams( }) } -export function getParams(target: HTMLElement): RawCustomizerParams { +function getParams(target: HTMLElement): RawCustomizerParams { const params = {} if (!target) return params diff --git a/app/web/src/helpers/hooks/useIdeState.ts b/app/web/src/helpers/hooks/useIdeState.ts index 2de05d4..7423dab 100644 --- a/app/web/src/helpers/hooks/useIdeState.ts +++ b/app/web/src/helpers/hooks/useIdeState.ts @@ -1,6 +1,7 @@ import { useReducer } from 'react' import { cadPackages } from 'src/helpers/cadPackages' import type { RootState } from '@react-three/fiber' +import type { RawCustomizerParams } from 'src/helpers/cadPackages/common' function withThunk(dispatch, getState) { return (actionOrThunk) => @@ -114,9 +115,9 @@ export interface State { type: 'INIT' | 'stl' | 'png' | 'geometry' data: any quality: 'low' | 'high' - customizerParams?: any - lastParameters?: any } + customizerParams?: any[] + currentParameters?: RawCustomizerParams layout: any camera: { dist?: number @@ -180,10 +181,9 @@ export const useIdeState = (): [State, (actionOrThunk: any) => any] => { ...state.objectData, type: payload.objectData?.type, data: payload.objectData?.data, - customizerParams: - payload.customizerParams || state.objectData.customizerParams, - lastParameters: payload.lastParameters, }, + customizerParams: payload.customizerParams || state.customizerParams, + currentParameters: payload.currentParameters, consoleMessages: payload.message ? [...state.consoleMessages, payload.message] : payload.message, @@ -197,6 +197,11 @@ export const useIdeState = (): [State, (actionOrThunk: any) => any] => { : payload.message, isLoading: false, } + case 'setCurrentCustomizerParams': + return { + ...state, + currentParameters: payload, + } case 'setLayout': return { ...state, @@ -282,7 +287,13 @@ export const requestRender = ({ }, }) .then( - ({ objectData, message, status, customizerParams, lastParameters }) => { + ({ + objectData, + message, + status, + customizerParams, + currentParameters, + }) => { if (status === 'error') { dispatch({ type: 'errorRender', @@ -296,7 +307,7 @@ export const requestRender = ({ message, lastRunCode: code, customizerParams, - lastParameters, + currentParameters, }, }) return objectData From 8dd8e2e749cfd7049c4e4ecc9c6512e477edb4fa Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sat, 7 Aug 2021 19:24:49 +1000 Subject: [PATCH 15/19] Tweak customizer styles and hide on non-jscad screens --- .../src/components/Customizer/Customizer.tsx | 72 +++++++++++++------ 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/app/web/src/components/Customizer/Customizer.tsx b/app/web/src/components/Customizer/Customizer.tsx index 9010328..d418538 100644 --- a/app/web/src/components/Customizer/Customizer.tsx +++ b/app/web/src/components/Customizer/Customizer.tsx @@ -1,10 +1,12 @@ import { useRender } from 'src/components/IdeWrapper/useRender' import { useIdeContext } from 'src/helpers/hooks/useIdeContext' import { genParams } from 'src/helpers/cadPackages/jsCad/jscadParams' +import { Switch } from '@headlessui/react' +import Svg from 'src/components/Svg/Svg' const Customizer = () => { - const [open, setOpen] = React.useState(true) - const [checked, setChecked] = React.useState(false) + const [open, setOpen] = React.useState(false) + const [shouldLiveUpdate, setShouldLiveUpdate] = React.useState(false) const ref = React.useRef() const jsCadCustomizerElement = ref.current const { state, thunkDispatch } = useIdeContext() @@ -20,14 +22,20 @@ const Customizer = () => { currentParameters || {}, (values, source) => { thunkDispatch({ type: 'setCurrentCustomizerParams', payload: values }) - if (checked) { + if (shouldLiveUpdate) { handleRender() } }, [] ) } - }, [jsCadCustomizerElement, customizerParams, currentParameters, checked]) + }, [ + jsCadCustomizerElement, + customizerParams, + currentParameters, + shouldLiveUpdate, + ]) + if (!state.customizerParams) return null return (
{
Parameters
-
- { - const newValue = !checked - if (newValue) handleRender() - setChecked(newValue) - }} - /> - -
+ {open && ( + <> +
+
Auto Update
+ { + setShouldLiveUpdate + if (newValue) handleRender() + setShouldLiveUpdate(newValue) + }} + className={`${ + shouldLiveUpdate ? 'bg-ch-purple-600' : 'bg-ch-gray-300' + } relative inline-flex items-center h-6 rounded-full w-11 mr-6`} + > + + + +
+ + )}
Date: Sat, 7 Aug 2021 11:32:03 +0200 Subject: [PATCH 16/19] don't allow group collapse/exp to triger render, only store values --- app/web/src/components/Customizer/Customizer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/web/src/components/Customizer/Customizer.tsx b/app/web/src/components/Customizer/Customizer.tsx index d418538..adcd82c 100644 --- a/app/web/src/components/Customizer/Customizer.tsx +++ b/app/web/src/components/Customizer/Customizer.tsx @@ -22,7 +22,7 @@ const Customizer = () => { currentParameters || {}, (values, source) => { thunkDispatch({ type: 'setCurrentCustomizerParams', payload: values }) - if (shouldLiveUpdate) { + if (shouldLiveUpdate && source !== 'group') { handleRender() } }, From dcd9d42d3273587a52691fd2c3399fa2e6368ec3 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sat, 7 Aug 2021 21:26:11 +1000 Subject: [PATCH 17/19] deeply compare old and new params --- app/web/src/components/Customizer/Customizer.tsx | 2 +- app/web/src/components/EditorMenu/helpers.ts | 1 + app/web/src/components/IdeEditor/IdeEditor.tsx | 1 + app/web/src/components/IdeViewer/IdeViewer.tsx | 1 + app/web/src/helpers/cadPackages/common.ts | 2 +- app/web/src/helpers/cadPackages/jsCad/jsCadController.ts | 2 +- app/web/src/helpers/hooks/use3dViewerResize.ts | 1 + app/web/src/helpers/hooks/useIdeState.ts | 3 ++- 8 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/web/src/components/Customizer/Customizer.tsx b/app/web/src/components/Customizer/Customizer.tsx index adcd82c..d418538 100644 --- a/app/web/src/components/Customizer/Customizer.tsx +++ b/app/web/src/components/Customizer/Customizer.tsx @@ -22,7 +22,7 @@ const Customizer = () => { currentParameters || {}, (values, source) => { thunkDispatch({ type: 'setCurrentCustomizerParams', payload: values }) - if (shouldLiveUpdate && source !== 'group') { + if (shouldLiveUpdate) { handleRender() } }, diff --git a/app/web/src/components/EditorMenu/helpers.ts b/app/web/src/components/EditorMenu/helpers.ts index 0ced278..6caaa14 100644 --- a/app/web/src/components/EditorMenu/helpers.ts +++ b/app/web/src/components/EditorMenu/helpers.ts @@ -74,6 +74,7 @@ export const makeStlDownloadHandler = camera: state.camera, quality: 'high', specialCadProcess, + parameters: state.currentParameters, }).then((result) => result && saveFile(result.data)) }) } diff --git a/app/web/src/components/IdeEditor/IdeEditor.tsx b/app/web/src/components/IdeEditor/IdeEditor.tsx index 2a514f5..1a5f6c6 100644 --- a/app/web/src/components/IdeEditor/IdeEditor.tsx +++ b/app/web/src/components/IdeEditor/IdeEditor.tsx @@ -62,6 +62,7 @@ const IdeEditor = ({ Loading }) => { code: state.code, viewerSize: state.viewerSize, camera: state.camera, + parameters: state.currentParameters, }) }) localStorage.setItem(makeCodeStoreKey(state.ideType), state.code) diff --git a/app/web/src/components/IdeViewer/IdeViewer.tsx b/app/web/src/components/IdeViewer/IdeViewer.tsx index 0ac5421..3aa0c10 100644 --- a/app/web/src/components/IdeViewer/IdeViewer.tsx +++ b/app/web/src/components/IdeViewer/IdeViewer.tsx @@ -211,6 +211,7 @@ const IdeViewer = ({ Loading }) => { code: state.code, viewerSize: state.viewerSize, camera, + parameters: state.currentParameters, }) } }) diff --git a/app/web/src/helpers/cadPackages/common.ts b/app/web/src/helpers/cadPackages/common.ts index 7c17760..1a5acc1 100644 --- a/app/web/src/helpers/cadPackages/common.ts +++ b/app/web/src/helpers/cadPackages/common.ts @@ -12,7 +12,7 @@ export const stlToGeometry = (url) => export interface RenderArgs { code: State['code'] - parameters: any + parameters?: RawCustomizerParams settings: { camera: State['camera'] viewerSize: State['viewerSize'] diff --git a/app/web/src/helpers/cadPackages/jsCad/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCad/jsCadController.ts index c40594d..f0088da 100644 --- a/app/web/src/helpers/cadPackages/jsCad/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCad/jsCadController.ts @@ -129,7 +129,7 @@ export const render: DefaultKernelExport['render'] = async ({ scriptWorker.postMessage({ action: 'init', baseURI, alias: [] }) } - if (parameters) { + if (parameters && currentParameters && JSON.stringify(parameters) !== JSON.stringify(currentParameters)) { // we are not evaluating code, but reacting to parameters change scriptWorker.postMessage({ action: 'updateParams', diff --git a/app/web/src/helpers/hooks/use3dViewerResize.ts b/app/web/src/helpers/hooks/use3dViewerResize.ts index 9ed6321..dd5fe24 100644 --- a/app/web/src/helpers/hooks/use3dViewerResize.ts +++ b/app/web/src/helpers/hooks/use3dViewerResize.ts @@ -26,6 +26,7 @@ export const use3dViewerResize = () => { code: state.code, viewerSize: { width, height }, camera: state.camera, + parameters: state.currentParameters, }) } }) diff --git a/app/web/src/helpers/hooks/useIdeState.ts b/app/web/src/helpers/hooks/useIdeState.ts index 7423dab..900ceee 100644 --- a/app/web/src/helpers/hooks/useIdeState.ts +++ b/app/web/src/helpers/hooks/useIdeState.ts @@ -183,7 +183,7 @@ export const useIdeState = (): [State, (actionOrThunk: any) => any] => { data: payload.objectData?.data, }, customizerParams: payload.customizerParams || state.customizerParams, - currentParameters: payload.currentParameters, + currentParameters: Object.keys(payload.currentParameters).length ? payload.currentParameters : state.currentParameters, consoleMessages: payload.message ? [...state.consoleMessages, payload.message] : payload.message, @@ -198,6 +198,7 @@ export const useIdeState = (): [State, (actionOrThunk: any) => any] => { isLoading: false, } case 'setCurrentCustomizerParams': + if (!Object.keys(payload).length) return state return { ...state, currentParameters: payload, From ff492fc1c7340587b570fa3fbd566b7a90dbd791 Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Sat, 7 Aug 2021 16:03:59 +0200 Subject: [PATCH 18/19] Update jscadParams.ts --- app/web/src/helpers/cadPackages/jsCad/jscadParams.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/web/src/helpers/cadPackages/jsCad/jscadParams.ts b/app/web/src/helpers/cadPackages/jsCad/jscadParams.ts index a397e45..503f9f1 100644 --- a/app/web/src/helpers/cadPackages/jsCad/jscadParams.ts +++ b/app/web/src/helpers/cadPackages/jsCad/jscadParams.ts @@ -94,7 +94,7 @@ export function genParams( if (min !== undefined) str += ` min="${min || ''}"` if (max !== undefined) str += ` max="${max || ''}"` if (value !== undefined) str += ` value="${value}"` - if (live !== undefined) str += ` live="${live ? 1 : 0}"` + str += ` live="${live ? 1 : 0}"` if (placeholder !== undefined) str += ` placeholder="${placeholder}"` return str + '/>' } @@ -160,7 +160,7 @@ export function genParams( if (inp.getAttribute('live') === '1') _callback('live') }) if (inp.getAttribute('live') !== '1') - inp.addEventListener('change', _callback) + inp.addEventListener('change', ()=>_callback('change')) }) function groupClick(evt) { From 2ea15df9d112f5c9f9dde6343068569e0ee64189 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sun, 8 Aug 2021 07:06:20 +1000 Subject: [PATCH 19/19] defer ping animation --- .../DelayedPingAnimation.tsx | 29 +++++++++++++++++++ .../src/components/IdeViewer/IdeViewer.tsx | 7 ++--- app/web/src/helpers/hooks/useIdeState.ts | 3 +- 3 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 app/web/src/components/DelayedPingAnimation/DelayedPingAnimation.tsx diff --git a/app/web/src/components/DelayedPingAnimation/DelayedPingAnimation.tsx b/app/web/src/components/DelayedPingAnimation/DelayedPingAnimation.tsx new file mode 100644 index 0000000..bfc4995 --- /dev/null +++ b/app/web/src/components/DelayedPingAnimation/DelayedPingAnimation.tsx @@ -0,0 +1,29 @@ + + +let timeoutId = 0 +const DelayedPingAnimation = ({isLoading: isLoading}: {isLoading: boolean}) => { + const [showLoading, setShowLoading] = React.useState(false) + React.useEffect(() => { + if (!isLoading && showLoading) { + setShowLoading(isLoading) + clearTimeout(timeoutId) + } else if (isLoading && !showLoading) { + timeoutId = setTimeout(() => { + setShowLoading(isLoading) + console.log('setloading') + }, 300) as unknown as number + } else if (!isLoading) { + setShowLoading(isLoading) + clearTimeout(timeoutId) + } + }, [isLoading]) + + if (showLoading && isLoading) return ( +
+
+
+ ) + return null +} + +export default DelayedPingAnimation diff --git a/app/web/src/components/IdeViewer/IdeViewer.tsx b/app/web/src/components/IdeViewer/IdeViewer.tsx index 3aa0c10..13d1db7 100644 --- a/app/web/src/components/IdeViewer/IdeViewer.tsx +++ b/app/web/src/components/IdeViewer/IdeViewer.tsx @@ -7,6 +7,7 @@ import { requestRender } from 'src/helpers/hooks/useIdeState' import texture from './dullFrontLitMetal.png' import { TextureLoader } from 'three/src/loaders/TextureLoader' import Customizer from 'src/components/Customizer/Customizer' + import DelayedPingAnimation from 'src/components/DelayedPingAnimation/DelayedPingAnimation' const loader = new TextureLoader() const colorMap = loader.load(texture) @@ -240,11 +241,7 @@ const IdeViewer = ({ Loading }) => { />
- {state.isLoading && ( -
-
-
- )} +
) diff --git a/app/web/src/helpers/hooks/useIdeState.ts b/app/web/src/helpers/hooks/useIdeState.ts index 900ceee..bd157b1 100644 --- a/app/web/src/helpers/hooks/useIdeState.ts +++ b/app/web/src/helpers/hooks/useIdeState.ts @@ -175,6 +175,7 @@ export const useIdeState = (): [State, (actionOrThunk: any) => any] => { case 'updateCode': return { ...state, code: payload } case 'healthyRender': + const currentParameters = (payload.currentParameters && Object.keys(payload.currentParameters).length) ? payload.currentParameters : state.currentParameters return { ...state, objectData: { @@ -183,7 +184,7 @@ export const useIdeState = (): [State, (actionOrThunk: any) => any] => { data: payload.objectData?.data, }, customizerParams: payload.customizerParams || state.customizerParams, - currentParameters: Object.keys(payload.currentParameters).length ? payload.currentParameters : state.currentParameters, + currentParameters, consoleMessages: payload.message ? [...state.consoleMessages, payload.message] : payload.message,