diff --git a/moodconsole/src/App.tsx b/moodconsole/src/App.tsx index 47ea6a4..442cb10 100644 --- a/moodconsole/src/App.tsx +++ b/moodconsole/src/App.tsx @@ -31,17 +31,93 @@ const Display: FC<{ ); }; +interface EffectParamsOption { + type: "slider"; + min: number; + max: number; + default: number; + step?: number; +} + +interface EffectOption { + function: string; + params: { [key: string]: EffectParamsOption } | undefined; +} + +interface EffectActive { + function: string; + params: { [key: string]: any }; +} + interface State { initialized: number; - current_effect: string; + chain: EffectActive[]; } interface Options { effects: { - available: string[]; + available: EffectOption[]; }; } +const ActiveEffect: FC<{ + availableEffects: EffectOption[]; + effect: EffectActive; + key: string; + onChange: (name: string, value: number) => void; +}> = ({ availableEffects, effect, onChange, key }) => { + const effectUsed = availableEffects.find( + (e) => e.function === effect.function + ); + + const children = (function () { + if ( + effectUsed && + effectUsed.params !== undefined && + effectUsed.params !== null + ) { + return Object.entries(effectUsed.params).map( + ([name, paramOptions], idx) => { + if (paramOptions.type === "slider") { + const currentValue = effect.params[name]; + const id = `${key}-input-${name}-${idx}`; + return ( +
+
+
{paramOptions.min}
+ onChange(name, parseFloat(e.target.value))} + step={paramOptions.step || 1} + /> +
{paramOptions.max}
+
+ +
+ ); + } + return null; + } + ); + } else { + return null; + } + })(); + + return ( + +

{effect.function}

+ {children} +
+ ); +}; + function App() { const [state, setState] = useState(undefined); const [options, setOptions] = useState(undefined); @@ -101,30 +177,99 @@ function App() { } }, [socket]); - const onEffectButtonClick = (name: string) => { - socket?.send( - JSON.stringify({ type: "mutation", payload: { current_effect: name } }) - ); + const propagateState = (state: State) => { + socket?.send(JSON.stringify({ type: "mutation", payload: state })); + }; + + const handleAvailableDrop = (id: string) => { + const [source, index, name] = id.split("-"); + if (source === "active" && state) { + // remove from chain + const stateCopy = JSON.parse(JSON.stringify(state)) as State; + stateCopy.chain.splice(parseInt(index), 1); + propagateState(stateCopy); + } + }; + + const handleChainDrop = (id: string) => { + const [source, index, name] = id.split("-"); + if (source === "available" && state) { + const stateCopy = JSON.parse(JSON.stringify(state)) as State; + const effect = options?.effects.available.filter( + (e) => e.function === name + )[0]; + if (effect) { + stateCopy.chain.push({ + function: effect.function, + params: {}, + }); + propagateState(stateCopy); + } + } }; return (
{options && state ? ( -
- Current Effect {state.current_effect} - {options.effects.available.map((effect) => { - return ( - - ); - })} +
+
{ + const id = e.dataTransfer.getData("application/json"); + handleAvailableDrop(id); + }} + onDragOver={(e) => { + e.preventDefault(); + }} + > + {options.effects.available.map((effect, index) => { + const key = `available-${index}-${effect.function}`; + return ( +
{ + e.dataTransfer.setData("application/json", key); + }} + > + {effect.function} +
+ ); + })} +
+
{ + const id = e.dataTransfer.getData("application/json"); + handleChainDrop(id); + }} + onDragOver={(e) => { + e.preventDefault(); + }} + > + {state.chain.map((effect, index) => { + const key = `active-${index}-${effect.function}`; + return ( +
{ + e.dataTransfer.setData("application/json", key); + }} + > + { + effect.params[name] = value; + propagateState(state); + }} + > +
+ ); + })} +
) : (
OFFLINE