drag-n-drop chain + dynamic params

This commit is contained in:
2021-04-06 00:10:04 +02:00
parent 8911be8350
commit f4c66d5b92

View File

@@ -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 (
<div>
<div className="flex">
<div className="text-sm">{paramOptions.min}</div>
<input
id={id}
type="range"
value={currentValue}
min={paramOptions.min}
max={paramOptions.max}
onChange={(e) => onChange(name, parseFloat(e.target.value))}
step={paramOptions.step || 1}
/>
<div className="text-sm">{paramOptions.max}</div>
</div>
<label className="text-sm text-gray-500" htmlFor={id}>
{name}
</label>
</div>
);
}
return null;
}
);
} else {
return null;
}
})();
return (
<Display color="green">
<p>{effect.function}</p>
{children}
</Display>
);
};
function App() {
const [state, setState] = useState<State | undefined>(undefined);
const [options, setOptions] = useState<Options | undefined>(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 (
<div>
{options && state ? (
<div className="font-mono flex justify-center flex-col">
<Display color="gray">Current Effect {state.current_effect}</Display>
{options.effects.available.map((effect) => {
return (
<Button
key={effect}
color="green"
onClick={() => {
onEffectButtonClick(effect);
}}
>
{effect}
</Button>
);
})}
<div className="flex flex-row">
<div
className="font-mono flex justify-start flex-col w-1/2"
onDrop={(e) => {
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 (
<div
draggable
key={key}
onDragStart={(e) => {
e.dataTransfer.setData("application/json", key);
}}
>
<Display color="gray">{effect.function}</Display>
</div>
);
})}
</div>
<div
className="flex justify-start flex-col border border-green-500 w-1/2"
onDrop={(e) => {
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 (
<div
draggable
key={key}
onDragStart={(e) => {
e.dataTransfer.setData("application/json", key);
}}
>
<ActiveEffect
key={key}
effect={effect}
availableEffects={options.effects.available}
onChange={(name, value) => {
effect.params[name] = value;
propagateState(state);
}}
></ActiveEffect>
</div>
);
})}
</div>
</div>
) : (
<div className="font-mono text-center text-8xl">OFFLINE</div>