Change how customizer params are applied #529
@@ -14,12 +14,23 @@ import {
|
|||||||
} from './customizerConverter'
|
} from './customizerConverter'
|
||||||
|
|
||||||
const Customizer = () => {
|
const Customizer = () => {
|
||||||
const [open, setOpen] = React.useState(false)
|
|
||||||
const [shouldLiveUpdate, setShouldLiveUpdate] = React.useState(false)
|
const [shouldLiveUpdate, setShouldLiveUpdate] = React.useState(false)
|
||||||
const { state, thunkDispatch } = useIdeContext()
|
const { state, thunkDispatch } = useIdeContext()
|
||||||
|
const isOpen = state.isCustomizerOpen
|
||||||
const customizerParams = state?.customizerParams
|
const customizerParams = state?.customizerParams
|
||||||
const currentParameters = state?.currentParameters || {}
|
const currentParameters = state?.currentParameters || {}
|
||||||
const handleRender = useRender()
|
const handleRender = useRender()
|
||||||
|
const toggleOpen = () => {
|
||||||
|
thunkDispatch({ type: 'setCustomizerOpenState', payload: !isOpen })
|
||||||
|
if (state.viewerContext === 'ide') {
|
||||||
|
// don't re-render on open/close in the project profile
|
||||||
|
setTimeout(() => handleRender())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleReset = () => {
|
||||||
|
thunkDispatch({ type: 'resetCustomizer' })
|
||||||
|
setTimeout(() => handleRender(true))
|
||||||
|
}
|
||||||
|
|
||||||
const updateCustomizerParam = (paramName: string, paramValue: any) => {
|
const updateCustomizerParam = (paramName: string, paramValue: any) => {
|
||||||
const payload = {
|
const payload = {
|
||||||
@@ -33,20 +44,20 @@ const Customizer = () => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`absolute inset-x-0 bottom-0 bg-ch-gray-600 bg-opacity-60 text-ch-gray-300 text-lg font-fira-sans ${
|
className={`absolute inset-x-0 bottom-0 bg-ch-gray-600 bg-opacity-60 text-ch-gray-300 text-lg font-fira-sans ${
|
||||||
open ? 'h-full max-h-96' : ''
|
isOpen ? 'h-full max-h-96' : ''
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex justify-between px-6 py-2 items-center">
|
<div className="flex justify-between px-6 py-2 items-center">
|
||||||
<div className="grid grid-flow-col-dense gap-6 items-center">
|
<div className="grid grid-flow-col-dense gap-6 items-center">
|
||||||
<button className="px-2" onClick={() => setOpen(!open)}>
|
<button className="px-2" onClick={toggleOpen}>
|
||||||
<Svg
|
<Svg
|
||||||
name="chevron-down"
|
name="chevron-down"
|
||||||
className={`h-8 w-8 ${!open && 'transform rotate-180'}`}
|
className={`h-8 w-8 ${!isOpen && 'transform rotate-180'}`}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<div>Parameters</div>
|
<div>Parameters</div>
|
||||||
</div>
|
</div>
|
||||||
{open && (
|
{isOpen && (
|
||||||
<>
|
<>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="font-fira-sans text-sm mr-4">Auto Update</div>
|
<div className="font-fira-sans text-sm mr-4">Auto Update</div>
|
||||||
@@ -66,11 +77,17 @@ const Customizer = () => {
|
|||||||
} inline-block w-4 h-4 transform bg-white rounded-full`}
|
} inline-block w-4 h-4 transform bg-white rounded-full`}
|
||||||
/>
|
/>
|
||||||
</Switch>
|
</Switch>
|
||||||
|
<button
|
||||||
|
className="px-4 py-1 rounded bg-ch-gray-300 text-ch-gray-600 mr-2"
|
||||||
|
onClick={handleReset}
|
||||||
|
>
|
||||||
|
Reset
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
className={`px-4 py-1 rounded bg-ch-gray-300 text-ch-gray-800 ${
|
className={`px-4 py-1 rounded bg-ch-gray-300 text-ch-gray-800 ${
|
||||||
shouldLiveUpdate && 'bg-opacity-30 cursor-default'
|
shouldLiveUpdate && 'bg-opacity-30 cursor-default'
|
||||||
}`}
|
}`}
|
||||||
onClick={handleRender}
|
onClick={() => handleRender()}
|
||||||
disabled={shouldLiveUpdate}
|
disabled={shouldLiveUpdate}
|
||||||
>
|
>
|
||||||
Update
|
Update
|
||||||
@@ -79,7 +96,9 @@ const Customizer = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={`${open ? 'h-full pb-32' : 'h-0'} overflow-y-auto px-12`}>
|
<div
|
||||||
|
className={`${isOpen ? 'h-full pb-32' : 'h-0'} overflow-y-auto px-12`}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
{customizerParams.map((param, index) => {
|
{customizerParams.map((param, index) => {
|
||||||
const otherProps = {
|
const otherProps = {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useIdeContext } from 'src/helpers/hooks/useIdeContext'
|
|||||||
import { useRender } from 'src/components/IdeWrapper/useRender'
|
import { useRender } from 'src/components/IdeWrapper/useRender'
|
||||||
import { encode, decode } from 'src/helpers/compress'
|
import { encode, decode } from 'src/helpers/compress'
|
||||||
import { isBrowser } from '@redwoodjs/prerender/browserUtils'
|
import { isBrowser } from '@redwoodjs/prerender/browserUtils'
|
||||||
|
import type { State } from 'src/helpers/hooks/useIdeState'
|
||||||
|
|
||||||
const scriptKey = 'encoded_script'
|
const scriptKey = 'encoded_script'
|
||||||
const scriptKeyV2 = 'encoded_script_v2'
|
const scriptKeyV2 = 'encoded_script_v2'
|
||||||
@@ -32,13 +33,17 @@ export function makeExternalUrl(resourceUrl: string): string {
|
|||||||
}#${fetchText}=${prepareDecodedUrl(resourceUrl)}`
|
}#${fetchText}=${prepareDecodedUrl(resourceUrl)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useIdeInit(cadPackage: string, code = '') {
|
export function useIdeInit(
|
||||||
|
cadPackage: State['ideType'],
|
||||||
|
code = '',
|
||||||
|
viewerContext: State['viewerContext'] = 'ide'
|
||||||
|
) {
|
||||||
const { thunkDispatch } = useIdeContext()
|
const { thunkDispatch } = useIdeContext()
|
||||||
const handleRender = useRender()
|
const handleRender = useRender()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
thunkDispatch({
|
thunkDispatch({
|
||||||
type: 'initIde',
|
type: 'initIde',
|
||||||
payload: { cadPackage, code },
|
payload: { cadPackage, code, viewerContext },
|
||||||
})
|
})
|
||||||
if (code) {
|
if (code) {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useIdeContext } from 'src/helpers/hooks/useIdeContext'
|
|||||||
|
|
||||||
export const useRender = () => {
|
export const useRender = () => {
|
||||||
const { state, thunkDispatch } = useIdeContext()
|
const { state, thunkDispatch } = useIdeContext()
|
||||||
return () => {
|
return (disableParams = false) => {
|
||||||
thunkDispatch((dispatch, getState) => {
|
thunkDispatch((dispatch, getState) => {
|
||||||
const state = getState()
|
const state = getState()
|
||||||
dispatch({ type: 'setLoading' })
|
dispatch({ type: 'setLoading' })
|
||||||
@@ -13,7 +13,7 @@ export const useRender = () => {
|
|||||||
code: state.code,
|
code: state.code,
|
||||||
viewerSize: state.viewerSize,
|
viewerSize: state.viewerSize,
|
||||||
camera: state.camera,
|
camera: state.camera,
|
||||||
parameters: state.currentParameters,
|
parameters: disableParams ? {} : state.currentParameters,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
localStorage.setItem(makeCodeStoreKey(state.ideType), state.code)
|
localStorage.setItem(makeCodeStoreKey(state.ideType), state.code)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect, useRef, lazy, Suspense } from 'react'
|
import { useState, useEffect, useRef } from 'react'
|
||||||
import { useAuth } from '@redwoodjs/auth'
|
import { useAuth } from '@redwoodjs/auth'
|
||||||
import { Link, navigate, routes } from '@redwoodjs/router'
|
import { Link, navigate, routes } from '@redwoodjs/router'
|
||||||
import Editor from 'rich-markdown-editor'
|
import Editor from 'rich-markdown-editor'
|
||||||
@@ -15,7 +15,6 @@ import CadPackage from 'src/components/CadPackage/CadPackage'
|
|||||||
import Gravatar from 'src/components/Gravatar/Gravatar'
|
import Gravatar from 'src/components/Gravatar/Gravatar'
|
||||||
import { useIdeInit } from 'src/components/EncodedUrl/helpers'
|
import { useIdeInit } from 'src/components/EncodedUrl/helpers'
|
||||||
import ProfileViewer from '../ProfileViewer/ProfileViewer'
|
import ProfileViewer from '../ProfileViewer/ProfileViewer'
|
||||||
import Svg from 'src/components/Svg/Svg'
|
|
||||||
import OpenscadStaticImageMessage from 'src/components/OpenscadStaticImageMessage/OpenscadStaticImageMessage'
|
import OpenscadStaticImageMessage from 'src/components/OpenscadStaticImageMessage/OpenscadStaticImageMessage'
|
||||||
import KeyValue from 'src/components/KeyValue/KeyValue'
|
import KeyValue from 'src/components/KeyValue/KeyValue'
|
||||||
|
|
||||||
@@ -51,7 +50,7 @@ const ProjectProfile = ({
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
}, [currentUser])
|
}, [currentUser])
|
||||||
useIdeInit(project?.cadPackage, project?.code)
|
useIdeInit(project?.cadPackage, project?.code, 'viewer')
|
||||||
const [newDescription, setNewDescription] = useState(project?.description)
|
const [newDescription, setNewDescription] = useState(project?.description)
|
||||||
const onDescriptionChange = (description) => setNewDescription(description())
|
const onDescriptionChange = (description) => setNewDescription(description())
|
||||||
const onEditSaveClick = () => {
|
const onEditSaveClick = () => {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ interface EditorModel {
|
|||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
ideType: 'INIT' | CadPackageType
|
ideType: 'INIT' | CadPackageType
|
||||||
|
viewerContext: 'ide' | 'viewer'
|
||||||
ideGuide?: string
|
ideGuide?: string
|
||||||
consoleMessages: { type: 'message' | 'error'; message: string; time: Date }[]
|
consoleMessages: { type: 'message' | 'error'; message: string; time: Date }[]
|
||||||
code: string
|
code: string
|
||||||
@@ -45,6 +46,7 @@ export interface State {
|
|||||||
}
|
}
|
||||||
customizerParams: CadhubParams[]
|
customizerParams: CadhubParams[]
|
||||||
currentParameters?: RawCustomizerParams
|
currentParameters?: RawCustomizerParams
|
||||||
|
isCustomizerOpen: boolean
|
||||||
layout: any
|
layout: any
|
||||||
camera: {
|
camera: {
|
||||||
dist?: number
|
dist?: number
|
||||||
@@ -71,6 +73,7 @@ const initialLayout = {
|
|||||||
|
|
||||||
export const initialState: State = {
|
export const initialState: State = {
|
||||||
ideType: 'INIT',
|
ideType: 'INIT',
|
||||||
|
viewerContext: 'ide',
|
||||||
consoleMessages: [
|
consoleMessages: [
|
||||||
{ type: 'message', message: 'Initialising', time: new Date() },
|
{ type: 'message', message: 'Initialising', time: new Date() },
|
||||||
],
|
],
|
||||||
@@ -83,6 +86,7 @@ export const initialState: State = {
|
|||||||
quality: 'low',
|
quality: 'low',
|
||||||
},
|
},
|
||||||
customizerParams: [],
|
customizerParams: [],
|
||||||
|
isCustomizerOpen: false,
|
||||||
layout: initialLayout,
|
layout: initialLayout,
|
||||||
camera: {},
|
camera: {},
|
||||||
viewerSize: { width: 0, height: 0 },
|
viewerSize: { width: 0, height: 0 },
|
||||||
@@ -103,17 +107,28 @@ const reducer = (state: State, { type, payload }): State => {
|
|||||||
'',
|
'',
|
||||||
ideType: payload.cadPackage,
|
ideType: payload.cadPackage,
|
||||||
ideGuide: initGuideMap[payload.cadPackage],
|
ideGuide: initGuideMap[payload.cadPackage],
|
||||||
|
viewerContext: payload.viewerContext,
|
||||||
}
|
}
|
||||||
case 'updateCode':
|
case 'updateCode':
|
||||||
return { ...state, code: payload }
|
return { ...state, code: payload }
|
||||||
|
case 'resetCustomizer':
|
||||||
|
const resetParameters = {}
|
||||||
|
state.customizerParams.forEach(({ name, initial }) => {
|
||||||
|
resetParameters[name] = initial
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
currentParameters: resetParameters,
|
||||||
|
}
|
||||||
case 'healthyRender':
|
case 'healthyRender':
|
||||||
const customizerParams: CadhubParams[] = payload.customizerParams || []
|
|
||||||
const currentParameters = {}
|
const currentParameters = {}
|
||||||
|
|
||||||
|
const customizerParams: CadhubParams[] = payload.customizerParams || []
|
||||||
customizerParams.forEach((param) => {
|
customizerParams.forEach((param) => {
|
||||||
currentParameters[param.name] =
|
currentParameters[param.name] =
|
||||||
typeof state?.currentParameters?.[param.name] !== 'undefined'
|
typeof state?.currentParameters?.[param.name] === 'undefined'
|
||||||
? state?.currentParameters?.[param.name]
|
? param.initial
|
||||||
: param.initial
|
: state?.currentParameters?.[param.name]
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
@@ -143,6 +158,11 @@ const reducer = (state: State, { type, payload }): State => {
|
|||||||
...state,
|
...state,
|
||||||
currentParameters: payload,
|
currentParameters: payload,
|
||||||
}
|
}
|
||||||
|
case 'setCustomizerOpenState':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
isCustomizerOpen: payload,
|
||||||
|
}
|
||||||
case 'setLayout':
|
case 'setLayout':
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
@@ -290,7 +310,7 @@ export const requestRender = ({
|
|||||||
return renderFn({
|
return renderFn({
|
||||||
code,
|
code,
|
||||||
settings: {
|
settings: {
|
||||||
parameters,
|
parameters: state.isCustomizerOpen ? parameters : {},
|
||||||
camera,
|
camera,
|
||||||
viewerSize,
|
viewerSize,
|
||||||
quality,
|
quality,
|
||||||
|
|||||||
Reference in New Issue
Block a user