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