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 { interface State {
initialized: number; initialized: number;
current_effect: string; chain: EffectActive[];
} }
interface Options { interface Options {
effects: { 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() { function App() {
const [state, setState] = useState<State | undefined>(undefined); const [state, setState] = useState<State | undefined>(undefined);
const [options, setOptions] = useState<Options | undefined>(undefined); const [options, setOptions] = useState<Options | undefined>(undefined);
@@ -101,31 +177,100 @@ function App() {
} }
}, [socket]); }, [socket]);
const onEffectButtonClick = (name: string) => { const propagateState = (state: State) => {
socket?.send( socket?.send(JSON.stringify({ type: "mutation", payload: state }));
JSON.stringify({ type: "mutation", payload: { current_effect: name } }) };
);
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 ( return (
<div> <div>
{options && state ? ( {options && state ? (
<div className="font-mono flex justify-center flex-col"> <div className="flex flex-row">
<Display color="gray">Current Effect {state.current_effect}</Display> <div
{options.effects.available.map((effect) => { className="font-mono flex justify-start flex-col w-1/2"
return ( onDrop={(e) => {
<Button const id = e.dataTransfer.getData("application/json");
key={effect} handleAvailableDrop(id);
color="green" }}
onClick={() => { onDragOver={(e) => {
onEffectButtonClick(effect); e.preventDefault();
}} }}
> >
{effect} {options.effects.available.map((effect, index) => {
</Button> 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>
<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> <div className="font-mono text-center text-8xl">OFFLINE</div>
)} )}