State controlled tray mvp

This commit is contained in:
Kurt Hutten
2021-09-12 19:54:31 +10:00
parent e7031e9c0d
commit 69c83d33b1
3 changed files with 138 additions and 114 deletions

View File

@@ -1,6 +1,7 @@
import { useState } from 'react' import { useState } from 'react'
import Svg from 'src/components/Svg/Svg' import Svg from 'src/components/Svg/Svg'
import { sidebarTopConfig, sidebarBottomConfig, sidebarCombinedConfig } from './sidebarConfig' import { sidebarTopConfig, sidebarBottomConfig, sidebarCombinedConfig } from './sidebarConfig'
import { useIdeContext } from 'src/helpers/hooks/useIdeContext'
function TabToggle({ item, className = "", active, onChange, onClick }) { function TabToggle({ item, className = "", active, onChange, onClick }) {
return ( return (
@@ -20,29 +21,24 @@ function TabToggle({ item, className = "", active, onChange, onClick }) {
} }
const IdeSideBar = () => { const IdeSideBar = () => {
const [selectedTab, setSelectedTab] = useState("") const { state, thunkDispatch } = useIdeContext()
const [lastOpen, setLastOpen] = useState("")
function onTabClick(name) { function onTabClick(name) {
return function() { return function() {
if (selectedTab === name) { thunkDispatch({type: 'settingsButtonClicked', payload: [name]})
setLastOpen(selectedTab)
setSelectedTab("")
} else if (selectedTab === "" && lastOpen === name) {
setSelectedTab(name)
}
} }
} }
const selectedTab = React.useMemo(() => sidebarCombinedConfig.find(item => item.name === state.sideTray[0]), [state.sideTray])
return ( return (
<section className="flex h-full bg-ch-gray-900"> <section className="flex h-full bg-ch-gray-900 border border-red-500">
<fieldset className="h-full flex flex-col justify-between bg-ch-gray-700"> <fieldset className="h-full flex flex-col justify-between bg-ch-gray-700">
<div> <div>
{ sidebarTopConfig.map((topItem, i) => ( { sidebarTopConfig.map((topItem, i) => (
<TabToggle <TabToggle
item={topItem} item={topItem}
active={ selectedTab === topItem.name } active={ state.sideTray[0] === topItem.name }
onChange={ () => setSelectedTab(topItem.name) } onChange={ () => onTabClick(topItem.name) }
onClick={ onTabClick(topItem.name) } onClick={ onTabClick(topItem.name) }
key={ 'tab-' + i } key={ 'tab-' + i }
/> />
@@ -52,18 +48,18 @@ const IdeSideBar = () => {
{ sidebarBottomConfig.map((bottomItem, i) => ( { sidebarBottomConfig.map((bottomItem, i) => (
<TabToggle <TabToggle
item={bottomItem} item={bottomItem}
active={ selectedTab === bottomItem.name } active={ state.sideTray[0] === bottomItem.name }
onChange={ () => setSelectedTab(bottomItem.name) } onChange={ () => onTabClick(bottomItem.name) }
onClick={ onTabClick(bottomItem.name) } onClick={ onTabClick(bottomItem.name) }
key={ 'tab-' + (sidebarTopConfig.length+i) } key={ 'tab-' + (sidebarTopConfig.length+i) }
/> />
))} ))}
</div> </div>
</fieldset> </fieldset>
{ sidebarCombinedConfig.find(item => item.name === selectedTab)?.panel && ( { selectedTab?.panel && (
<div className="w-56 bg-ch-gray-900 text-ch-gray-300 border border-ch-pink-800 border-opacity-30" style={{ height: 'calc(100% - 6px)', margin: '3px'}}> <div className="w-56 bg-ch-gray-900 text-ch-gray-300 border border-ch-pink-800 border-opacity-30" style={{ height: 'calc(100% - 6px)', margin: '3px'}}>
<h2 className="flex items-center h-9 px-4 bg-ch-pink-800 bg-opacity-30">{ selectedTab }</h2> <h2 className="flex items-center h-9 px-4 bg-ch-pink-800 bg-opacity-30">{ selectedTab.name }</h2>
{ sidebarCombinedConfig.find(item => item.name === selectedTab).panel } { selectedTab.panel }
</div> </div>
) } ) }
</section> </section>

View File

@@ -1,5 +1,6 @@
import React, { ReactNode } from 'react' import React, { ReactNode } from 'react'
import { SvgNames } from 'src/components/Svg/Svg' import { SvgNames } from 'src/components/Svg/Svg'
import { useIdeContext } from 'src/helpers/hooks/useIdeContext'
interface SidebarConfigType { interface SidebarConfigType {
name: string, name: string,
@@ -67,7 +68,7 @@ export const sidebarBottomConfig : SidebarConfigType[] = [
name: 'Settings', name: 'Settings',
icon: 'gear', icon: 'gear',
disabled: false, disabled: false,
panel: <SettingsMenu />, panel: <SettingsMenu parentName="Settings"/>,
}, },
] ]
@@ -76,14 +77,25 @@ export const sidebarCombinedConfig = [
...sidebarBottomConfig, ...sidebarBottomConfig,
] ]
function SettingsMenu() { function SettingsMenu({parentName}: {parentName: string}) {
const { state, thunkDispatch } = useIdeContext()
return ( return (
<article className=""> <article className="">
{ settingsConfig.map(item => ( { settingsConfig.map(item => (
<details key={'settings-tray-'+item.name}> <li className="list-none" key={'settings-tray-'+item.name}>
<summary className="px-2 py-2 bg-ch-pink-800 bg-opacity-10 my-px">{ item.title }</summary> <button className="px-2 py-2 bg-ch-pink-800 bg-opacity-10 my-px" onClick={() => {
{ item.content } console.log('i was clicked')
</details> thunkDispatch((dispatch) => dispatch({type: 'settingsButtonClicked', payload:[parentName, item.name]}))
}} >{ item.title }</button>
{ state.sideTray.slice(-1)[0] === item.name && item.content }
</li>
// <details key={'settings-tray-'+item.name} open={state.sideTray.slice(-1)[0] === item.name}>
// <summary className="px-2 py-2 bg-ch-pink-800 bg-opacity-10 my-px"
// onClick={() => thunkDispatch((dispatch) => dispatch({type: 'settingsButtonClicked', payload:[parentName, item.name]}))}
// >{ item.title }hi there</summary>
// { state.sideTray.slice(-1)[0] === item.name && item.content }
// {state.sideTray.slice(-1)[0]}
// </details>
))} ))}
</article> </article>
) )

View File

@@ -115,6 +115,7 @@ export interface State {
viewerSize: { width: number; height: number } viewerSize: { width: number; height: number }
isLoading: boolean isLoading: boolean
threeInstance: RootState threeInstance: RootState
sideTray: string[] // could probably be an array of a union type
} }
const code = '' const code = ''
@@ -146,103 +147,118 @@ export const initialState: State = {
viewerSize: { width: 0, height: 0 }, viewerSize: { width: 0, height: 0 },
isLoading: false, isLoading: false,
threeInstance: null, threeInstance: null,
sideTray: [],
} }
export const useIdeState = (): [State, (actionOrThunk: any) => any] => { const reducer = (state: State, { type, payload }): State => {
const reducer = (state: State, { type, payload }): State => { console.log('reducing')
switch (type) { switch (type) {
case 'initIde': case 'initIde':
return {
...state,
code:
payload.code ||
// localStorage.getItem(makeCodeStoreKey(payload.cadPackage)) ||
initCodeMap[payload.cadPackage] ||
'',
ideType: payload.cadPackage,
}
case 'updateCode':
return { ...state, code: payload }
case 'healthyRender':
const customizerParams: CadhubParams[] = payload?.customizerParams?.length
? payload.customizerParams
: state.customizerParams
const currentParameters = {}
customizerParams.forEach((param) => {
currentParameters[param.name] =
typeof state?.currentParameters?.[param.name] !== 'undefined'
? state?.currentParameters?.[param.name]
: param.initial
})
return {
...state,
objectData: {
...state.objectData,
type: payload.objectData?.type,
data: payload.objectData?.data,
},
customizerParams,
currentParameters,
consoleMessages: payload.message
? [...state.consoleMessages, payload.message]
: payload.message,
isLoading: false,
}
case 'errorRender':
return {
...state,
consoleMessages: payload.message
? [...state.consoleMessages, payload.message]
: payload.message,
isLoading: false,
}
case 'setCurrentCustomizerParams':
if (!Object.keys(payload || {}).length) return state
return {
...state,
currentParameters: payload,
}
case 'setLayout':
return {
...state,
layout: payload.message,
}
case 'updateCamera':
return {
...state,
camera: payload.camera,
}
case 'updateViewerSize':
return {
...state,
viewerSize: payload.viewerSize,
}
case 'setLoading':
return {
...state,
isLoading: true,
}
case 'resetLoading':
return {
...state,
isLoading: false,
}
case 'resetLayout':
return {
...state,
layout: initialLayout,
}
case 'setThreeInstance':
return {
...state,
threeInstance: payload,
}
case 'settingsButtonClicked':
const isReClick =
state.sideTray.length &&
state.sideTray.length === payload.length &&
state.sideTray.every((original, index) => original === payload[index])
if (isReClick) {
return { return {
...state, ...state,
code: sideTray: state.sideTray.slice(0, -1),
payload.code ||
// localStorage.getItem(makeCodeStoreKey(payload.cadPackage)) ||
initCodeMap[payload.cadPackage] ||
'',
ideType: payload.cadPackage,
} }
case 'updateCode': }
return { ...state, code: payload } return {
case 'healthyRender': ...state,
const customizerParams: CadhubParams[] = payload?.customizerParams sideTray: payload,
?.length }
? payload.customizerParams default:
: state.customizerParams return state
const currentParameters = {}
customizerParams.forEach((param) => {
currentParameters[param.name] =
typeof state?.currentParameters?.[param.name] !== 'undefined'
? state?.currentParameters?.[param.name]
: param.initial
})
return {
...state,
objectData: {
...state.objectData,
type: payload.objectData?.type,
data: payload.objectData?.data,
},
customizerParams,
currentParameters,
consoleMessages: payload.message
? [...state.consoleMessages, payload.message]
: payload.message,
isLoading: false,
}
case 'errorRender':
return {
...state,
consoleMessages: payload.message
? [...state.consoleMessages, payload.message]
: payload.message,
isLoading: false,
}
case 'setCurrentCustomizerParams':
if (!Object.keys(payload || {}).length) return state
return {
...state,
currentParameters: payload,
}
case 'setLayout':
return {
...state,
layout: payload.message,
}
case 'updateCamera':
return {
...state,
camera: payload.camera,
}
case 'updateViewerSize':
return {
...state,
viewerSize: payload.viewerSize,
}
case 'setLoading':
return {
...state,
isLoading: true,
}
case 'resetLoading':
return {
...state,
isLoading: false,
}
case 'resetLayout':
return {
...state,
layout: initialLayout,
}
case 'setThreeInstance':
return {
...state,
threeInstance: payload,
}
default:
return state
}
} }
}
export const useIdeState = (): [State, (actionOrThunk: any) => any] => {
const [state, dispatch] = useReducer(reducer, initialState) const [state, dispatch] = useReducer(reducer, initialState)
mutableState = state mutableState = state
const getState = (): State => mutableState const getState = (): State => mutableState